Work in progress: Swap out onebox code for onebox gem

This commit is contained in:
Robin Ward 2014-01-27 15:09:09 -05:00 committed by Neil Lalonde
parent a4e28eadd0
commit e453bfa073
76 changed files with 44 additions and 2510 deletions

View File

@ -72,6 +72,8 @@ gem 'redis', :require => ["redis", "redis/connection/hiredis"]
gem 'active_model_serializers'
gem 'onebox', git: 'https://github.com/dysania/onebox.git'
# we had issues with latest, stick to the rev till we figure this out
# PR that makes it all hang together welcome
gem 'ember-rails'

View File

@ -1,3 +1,15 @@
GIT
remote: https://github.com/dysania/onebox.git
revision: 1323ec18966b6398acc290ff451e065d1ff2ecb3
specs:
onebox (1.1.0)
hexpress (~> 1.2)
moneta (~> 0.7)
multi_json (~> 1.7)
mustache (~> 0.99)
nokogiri (~> 1.6.1)
opengraph_parser (~> 0.2.3)
PATH
remote: vendor/gems/discourse_plugin
specs:
@ -120,6 +132,7 @@ GEM
guess_html_encoding (0.0.9)
handlebars-source (1.1.2)
hashie (2.0.5)
hexpress (1.2.0)
highline (1.6.20)
hike (1.2.3)
hiredis (0.4.5)
@ -158,11 +171,12 @@ GEM
metaclass (0.0.1)
method_source (0.8.2)
mime-types (1.25.1)
mini_portile (0.5.1)
mini_portile (0.5.2)
minitest (4.7.5)
mocha (0.14.0)
metaclass (~> 0.0.1)
mock_redis (0.9.0)
moneta (0.7.20)
msgpack (0.5.7)
multi_json (1.8.2)
multipart-post (1.2.0)
@ -170,7 +184,7 @@ GEM
net-scp (1.1.2)
net-ssh (>= 2.6.5)
net-ssh (2.7.0)
nokogiri (1.6.0)
nokogiri (1.6.1)
mini_portile (~> 0.5.0)
oauth (0.4.7)
oauth2 (0.8.1)
@ -208,6 +222,9 @@ GEM
omniauth-twitter (1.0.1)
multi_json (~> 1.3)
omniauth-oauth (~> 1.0)
opengraph_parser (0.2.3)
addressable
nokogiri
openid-redis-store (0.0.2)
redis
ruby-openid
@ -429,6 +446,7 @@ DEPENDENCIES
omniauth-oauth2
omniauth-openid
omniauth-twitter
onebox!
openid-redis-store
pg (= 0.15.1)
pry-nav

View File

@ -1,3 +1,5 @@
require_dependency 'oneboxer'
class PostAnalyzer
def initialize(raw, topic_id)

View File

@ -1,7 +1,6 @@
# Post processing that we can do after a post has already been cooked.
# For example, inserting the onebox content, or image sizes/thumbnails.
require_dependency "oneboxer"
require_dependency 'url_helper'
class CookedPostProcessor

View File

@ -1,14 +1,5 @@
require 'open-uri'
require 'digest/sha1'
require_dependency 'oneboxer/base'
require_dependency 'oneboxer/whitelist'
Dir["#{Rails.root}/lib/oneboxer/*_onebox.rb"].each {|f|
require_dependency(f.split('/')[-2..-1].join('/'))
}
module Oneboxer
extend Oneboxer::Base
# keep reloaders happy
unless defined? Oneboxer::Result
@ -23,66 +14,26 @@ module Oneboxer
end
end
Dir["#{Rails.root}/lib/oneboxer/*_onebox.rb"].sort.each do |f|
add_onebox "Oneboxer::#{Pathname.new(f).basename.to_s.gsub(/\.rb$/, '').classify}".constantize
def self.preview(url, options=nil)
options ||= {}
Oneboxer.invalidate(url) if options[:invalidate_oneboxes]
Onebox.preview(url, cache: Rails.cache).placeholder_html
end
def self.default_expiry
1.day
def self.onebox(url, options=nil)
options ||= {}
Oneboxer.invalidate(url) if options[:invalidate_oneboxes]
Onebox.preview(url, cache: Rails.cache).to_s
end
def self.oneboxer_exists_for_url?(url)
Whitelist.entry_for_url(url) || matchers.any? { |matcher| url =~ matcher.regexp }
def self.oneboxer_exists_for_url?(url)
Onebox.has_matcher?(url)
end
# Return a oneboxer for a given URL
def self.onebox_for_url(url)
matchers.each do |matcher|
regexp = matcher.regexp
klass = matcher.klass
regexp = regexp.call if regexp.class == Proc
return klass.new(url) if url =~ regexp
end
nil
def self.invalidate(url)
Rails.cache.delete(url)
end
# Retrieve the onebox for a url without caching
def self.onebox_nocache(url)
oneboxer = onebox_for_url(url)
return oneboxer.onebox if oneboxer.present?
whitelist_entry = Whitelist.entry_for_url(url)
if whitelist_entry.present?
# TODO - only download HEAD section
# TODO - sane timeout
# TODO - FAIL if for any reason you are downloading more that 5000 bytes
page_html = open(url).read
if page_html.present?
doc = Nokogiri::HTML(page_html)
if whitelist_entry.allows_oembed?
# See if if it has an oembed thing we can use
(doc/"link[@type='application/json+oembed']").each do |oembed|
return OembedOnebox.new(oembed[:href]).onebox
end
(doc/"link[@type='text/json+oembed']").each do |oembed|
return OembedOnebox.new(oembed[:href]).onebox
end
end
# Check for opengraph
open_graph = Oneboxer.parse_open_graph(doc)
return OpenGraphOnebox.new(url, open_graph).onebox if open_graph.present?
end
end
nil
rescue OpenURI::HTTPError
nil
end
# Parse URLs out of HTML, returning the document when finished.
def self.each_onebox_link(string_or_doc)
doc = string_or_doc
@ -126,62 +77,5 @@ module Oneboxer
Result.new(doc, changed)
end
def self.cache_key_for(url)
"onebox:#{Digest::SHA1.hexdigest(url)}"
end
def self.preview_cache_key_for(url)
"onebox:preview:#{Digest::SHA1.hexdigest(url)}"
end
def self.render_from_cache(url)
Rails.cache.read(cache_key_for(url))
end
# Cache results from a onebox call
def self.fetch_and_cache(url, args)
contents, preview = onebox_nocache(url)
return nil if contents.blank?
Rails.cache.write(cache_key_for(url), contents, expires_in: default_expiry)
if preview.present?
Rails.cache.write(preview_cache_key_for(url), preview, expires_in: default_expiry)
end
[contents, preview]
end
def self.invalidate(url)
Rails.cache.delete(cache_key_for(url))
end
def self.preview(url, args={})
# Look for a preview
cached = Rails.cache.read(preview_cache_key_for(url)) unless args[:no_cache].present?
return cached if cached.present?
# Try the full version
cached = render_from_cache(url)
return cached if cached.present?
# If that fails, look it up
contents, cached = fetch_and_cache(url, args)
return cached if cached.present?
contents
end
# Return the cooked content for a url, caching the result for performance
def self.onebox(url, args={})
if args[:invalidate_oneboxes]
# Remove the onebox from the cache
Oneboxer.invalidate(url)
else
contents = render_from_cache(url)
return contents if contents.present?
end
fetch_and_cache(url, args)
end
end

View File

@ -1,12 +0,0 @@
require_dependency 'oneboxer/base_onebox'
module Oneboxer
class AudioOnebox < BaseOnebox
matcher /^https?:\/\/.*\.mp3$/
def onebox
"<audio controls><source src='#{@url}'><a href='#{@url}'>#{@url}</a></audio>"
end
end
end

View File

@ -1,17 +0,0 @@
require_dependency 'oneboxer/base_onebox'
module Oneboxer
class FlashVideoOnebox < BaseOnebox
matcher /^https?:\/\/.*\.(swf|flv)$/
def onebox
if SiteSetting.enable_flash_video_onebox
"<object width='100%' height='100%' wmode='opaque'><param name='#{@url}' value='#{@url}'><embed src='#{@url}' width='100%' height='100%' wmode='opaque'></embed></object>"
else
"<a href='#{@url}'>#{@url}</a>"
end
end
end
end

View File

@ -1,13 +0,0 @@
require_dependency 'oneboxer/base_onebox'
module Oneboxer
class ImageOnebox < BaseOnebox
matcher /^(https?:)?\/\/.+\.(png|jpg|jpeg|gif|bmp|tif|tiff)$/i
def onebox
Oneboxer::BaseOnebox.image_html(@url, nil, @url)
end
end
end

View File

@ -1,13 +0,0 @@
require_dependency 'oneboxer/base_onebox'
module Oneboxer
class VideoOnebox < BaseOnebox
matcher /^https?:\/\/.*\.(mov|mp4)$/
def onebox
"<video controls><source src='#{@url}'><a href='#{@url}'>#{@url}</a></video>"
end
end
end

View File

@ -1,44 +0,0 @@
require_dependency 'oneboxer/handlebars_onebox'
module Oneboxer
class AmazonOnebox < HandlebarsOnebox
matcher /^https?:\/\/(?:www\.)?amazon\.(com\.au|com|br|mx|ca|at|cn|fr|de|it|es|in|co\.jp|co\.uk)\/.*$/
favicon 'amazon.png'
def template
template_path("simple_onebox")
end
# Use the mobile version of the site
def translate_url
# If we're already mobile don't translate the url
return @url if @url =~ /https?:\/\/www\.amazon\.com\/gp\/aw\/d\//
m = @url.match(/(?:d|g)p\/(?:product\/)?(?<id>[^\/]+)(?:\/|$)/mi)
return "http://www.amazon.com/gp/aw/d/" + URI::encode(m[:id]) if m.present?
@url
end
def parse(data)
html_doc = Nokogiri::HTML(data)
result = {}
result[:title] = html_doc.at("h1")
result[:title] = result[:title].inner_text.strip if result[:title].present?
image = html_doc.at("#main-image")
result[:image] = image['src'] if image
result[:by_info] = html_doc.at("#by-line")
result[:by_info] = BaseOnebox.remove_whitespace(BaseOnebox.replace_tags_with_spaces(result[:by_info].inner_html)) if result[:by_info].present?
# not many CSS selectors to work with here, go with the first span in about-item ID
summary = html_doc.at("#about-item span")
result[:text] = summary.inner_html if summary.present?
result
end
end
end

View File

@ -1,35 +0,0 @@
require_dependency 'oneboxer/handlebars_onebox'
module Oneboxer
class AndroidAppStoreOnebox < HandlebarsOnebox
matcher /^https?:\/\/play\.google\.com\/.+$/
favicon 'google_play.png'
def template
template_path('simple_onebox')
end
def parse(data)
html_doc = Nokogiri::HTML(data)
result = {}
m = html_doc.at("h1.doc-banner-title")
result[:title] = m.inner_text if m
m = html_doc.at("div#doc-original-text")
if m
result[:text] = BaseOnebox.replace_tags_with_spaces(m.inner_html)
result[:text] = result[:text][0..MAX_TEXT]
end
m = html_doc.at("div.doc-banner-icon img")
result[:image] = m['src'] if m
result
end
end
end

View File

@ -1,37 +0,0 @@
require_dependency 'oneboxer/handlebars_onebox'
module Oneboxer
class AppleAppOnebox < HandlebarsOnebox
matcher /^https?:\/\/itunes\.apple\.com\/.+$/
favicon 'apple.png'
# Don't masquerade as mobile
def http_params
{}
end
def template
template_path('simple_onebox')
end
def parse(data)
html_doc = Nokogiri::HTML(data)
result = {}
m = html_doc.at("h1")
result[:title] = m.inner_text if m
m = html_doc.at("h4 ~ p")
result[:text] = m.inner_text[0..MAX_TEXT] if m
m = html_doc.at(".product img.artwork")
result[:image] = m['src'] if m
result
end
end
end

View File

@ -1,58 +0,0 @@
module Oneboxer
class << self
def parse_open_graph(doc)
result = {}
%w(title type image url description image:width image:height).each do |prop|
node = doc.at("/html/head/meta[@property='og:#{prop}']")
result[prop] = (node['content'] || node['value']) if node
end
# If there's no title, try using the page's title
if result['title'].blank?
result['title'] = doc.title
end
# If there's no description, try and get one from the meta tags
if result['description'].blank?
node = doc.at("/html/head/meta[@name='description']")
result['description'] = node['content'] if node
end
if result['description'].blank?
node = doc.at("/html/head/meta[@name='Description']")
result['description'] = node['content'] if node
end
%w(image:width image:height).each do |prop|
# Some sane max width
if result[prop] && result[prop].to_i < 100
result[prop.sub(":","_")] = result[prop]
end
result[prop] = nil
end
result
end
end
class Matcher
attr_reader :regexp, :klass
def initialize(klass)
@klass = klass
@regexp = klass.regexp
end
end
module Base
def matchers
@matchers ||= []
end
def add_onebox(klass)
matchers << Matcher.new(klass)
end
end
end

View File

@ -1,63 +0,0 @@
require 'open-uri'
module Oneboxer
class BaseOnebox
class << self
attr_accessor :regexp
attr_accessor :favicon_file
def matcher(regexp=nil,&blk)
self.regexp = regexp || blk
end
def favicon(favicon_file)
self.favicon_file = "favicons/#{favicon_file}"
end
def remove_whitespace(s)
s.gsub /\n/, ''
end
def image_html(url, title, page_url)
"<a href='#{page_url}' target='_blank'><img src='#{url}' alt='#{title}'></a>"
end
def replace_tags_with_spaces(s)
s.gsub /<[^>]+>/, ' '
end
def uriencode(val)
URI.escape(val, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
end
# Replace any occurence of a HTTP or HTTPS URL in the string with the protocol-agnostic variant
def replace_agnostic(var)
var.gsub! /https?:\/\//, '//' if var.is_a? String
end
# Add wmode=opaque to the iframe src URL so that the flash player is rendered within the document flow instead of on top
def append_embed_wmode(var)
var.gsub! /(src="[^"]+)/, '\1&wmode=opaque"' if var.is_a? String
end
end
def initialize(url, opts={})
@url = url
@opts = opts
end
def translate_url
@url
end
def nice_host
host = URI.parse(@url).host
host.nil? ? '' : host.gsub('www.', '')
rescue URI::InvalidURIError
'' # In case there is a problem with the URL, we just won't set the host
end
end
end

View File

@ -1,13 +0,0 @@
require_dependency 'oneboxer/oembed_onebox'
module Oneboxer
class BliptvOnebox < OembedOnebox
matcher /^https?\:\/\/blip\.tv\/.+$/
def oembed_endpoint
"http://blip.tv/oembed/?url=#{BaseOnebox.uriencode(@url)}&width=300"
end
end
end

View File

@ -1,26 +0,0 @@
require 'net/http'
require_dependency 'oneboxer/base_onebox'
module Oneboxer
class ClassicGoogleMapsOnebox < BaseOnebox
matcher /^(https?:)?\/\/(maps\.google\.[\w.]{2,}|goo\.gl)\/maps?.+$/
def onebox
@url = get_long_url(@url) if @url.include?("//goo.gl/maps/")
"<iframe src='#{@url}&output=embed' width='690px' height='400px' frameborder='0' style='border:0'></iframe>" if @url.present?
end
def get_long_url(url)
uri = URI(url)
http = Net::HTTP.start(uri.host, uri.port)
http.open_timeout = 1
http.read_timeout = 1
response = http.head(uri.path)
response["Location"] if response.code == "301"
rescue
nil
end
end
end

View File

@ -1,14 +0,0 @@
require_dependency 'oneboxer/oembed_onebox'
module Oneboxer
class ClikthroughOnebox < OembedOnebox
matcher /^https?:\/\/(?:www\.)?clikthrough\.com\/theater\/video\/\d+$/
def oembed_endpoint
"http://clikthrough.com/services/oembed?url=#{BaseOnebox.uriencode(@url)}"
end
end
end

View File

@ -1,14 +0,0 @@
require_dependency 'oneboxer/oembed_onebox'
module Oneboxer
class CollegeHumorOnebox < OembedOnebox
matcher /^https?\:\/\/www\.collegehumor\.com\/video\/.*$/
def oembed_endpoint
"http://www.collegehumor.com/oembed.json?url=#{BaseOnebox.uriencode(@url)}"
end
end
end

View File

@ -1,14 +0,0 @@
require_dependency 'oneboxer/oembed_onebox'
module Oneboxer
class DailymotionOnebox < OembedOnebox
matcher /^https?:\/\/(?:www\.)?dailymotion\.com\/.+$/
def oembed_endpoint
"http://www.dailymotion.com/api/oembed/?url=#{BaseOnebox.uriencode(@url)}"
end
end
end

View File

@ -1,97 +0,0 @@
require_dependency 'oneboxer/oembed_onebox'
require_dependency 'freedom_patches/rails4'
module Oneboxer
class DiscourseLocalOnebox < BaseOnebox
include ActionView::Helpers::DateHelper
matcher do
Regexp.new "^#{Discourse.base_url.gsub(".","\\.")}.*$", true
end
def onebox
uri = URI::parse(@url)
route = Rails.application.routes.recognize_path(uri.path)
args = {original_url: @url}
# Figure out what kind of onebox to show based on the URL
case route[:controller]
# when 'users'
# user = User.where(username_lower: route[:username].downcase).first
# return nil unless user
# return @url unless Guardian.new.can_see?(user)
# args.merge! avatar: PrettyText.avatar_img(user.avatar_template, 'tiny'), username: user.username
# args[:bio] = user.bio_cooked if user.bio_cooked.present?
# @template = 'user'
when 'topics'
linked = "<a href='#{@url}'>#{@url}</a>"
if route[:post_number].present? && route[:post_number].to_i > 1
# Post Link
post = Post.where(topic_id: route[:topic_id], post_number: route[:post_number].to_i).first
return linked unless post
return linked unless Guardian.new.can_see?(post)
topic = post.topic
slug = Slug.for(topic.title)
excerpt = post.excerpt(SiteSetting.post_onebox_maxlength)
excerpt.gsub!("\n"," ")
# hack to make it render for now
excerpt.gsub!("[/quote]", "[quote]")
quote = "[quote=\"#{post.user.username}, topic:#{topic.id}, slug:#{slug}, post:#{post.post_number}\"]#{excerpt}[/quote]"
cooked = PrettyText.cook(quote)
return cooked
else
# Topic Link
topic = Topic.where(id: route[:topic_id].to_i).includes(:user).first
return linked unless topic
return linked unless Guardian.new.can_see?(topic)
post = topic.posts.first
posters = topic.posters_summary.map do |p|
{
username: p[:user].username,
avatar: PrettyText.avatar_img(p[:user].avatar_template, 'tiny'),
description: p[:description],
extras: p[:extras]
}
end
category = topic.category
if category
category = "<a href=\"/category/#{category.slug}\" class=\"badge badge-category\" style=\"background-color: ##{category.color}; color: ##{category.text_color}\">#{category.name}</a>"
end
quote = post.excerpt(SiteSetting.post_onebox_maxlength)
args.merge! title: topic.title,
avatar: PrettyText.avatar_img(topic.user.avatar_template, 'tiny'),
posts_count: topic.posts_count,
last_post: FreedomPatches::Rails4.time_ago_in_words(topic.last_posted_at, false, scope: :'datetime.distance_in_words_verbose'),
age: FreedomPatches::Rails4.time_ago_in_words(topic.created_at, false, scope: :'datetime.distance_in_words_verbose'),
views: topic.views,
posters: posters,
quote: quote,
category: category,
topic: topic.id
@template = 'topic'
end
end
return nil unless @template
Mustache.render(File.read("#{Rails.root}/lib/oneboxer/templates/discourse_#{@template}_onebox.handlebars"), args)
rescue ActionController::RoutingError
nil
end
end
end

View File

@ -1,14 +0,0 @@
require_dependency 'oneboxer/oembed_onebox'
module Oneboxer
class DotsubOnebox < OembedOnebox
matcher /^https?:\/\/(?:www\.)?dotsub\.com\/.+$/
def oembed_endpoint
"http://dotsub.com/services/oembed?url=#{BaseOnebox.uriencode(@url)}"
end
end
end

View File

@ -1,24 +0,0 @@
require_dependency 'oneboxer/oembed_onebox'
module Oneboxer
class FlickrOnebox < BaseOnebox
matcher /^https?\:\/\/.*\.flickr\.com\/.*$/
def onebox
page_html = open(@url).read
return nil if page_html.blank?
doc = Nokogiri::HTML(page_html)
# Flikrs oembed just stopped returning images for no reason. Let's use opengraph instead.
open_graph = Oneboxer.parse_open_graph(doc)
# A site is supposed to supply all the basic og attributes, but some don't (like deviant art)
# If it just has image and no title, embed it as an image.
return BaseOnebox.image_html(open_graph['image'], nil, @url) if open_graph['image'].present?
nil
end
end
end

View File

@ -1,10 +0,0 @@
require_dependency 'oneboxer/oembed_onebox'
module Oneboxer
class FunnyOrDieOnebox < OembedOnebox
matcher /^https?\:\/\/(www\.)?funnyordie\.com\/videos\/.*$/
def oembed_endpoint
"http://www.funnyordie.com/oembed.json?url=#{BaseOnebox.uriencode(@url)}"
end
end
end

View File

@ -1,29 +0,0 @@
require_dependency 'oneboxer/handlebars_onebox'
module Oneboxer
class GistOnebox < HandlebarsOnebox
matcher /^https?:\/\/gist\.github\.com/
favicon 'github.png'
def translate_url
m = @url.match(/gist\.github\.com\/([^\/]+\/)?(?<id>[0-9a-f]+)/mi)
return "https://api.github.com/gists/#{m[:id]}" if m
end
def parse(data)
parsed = JSON.parse(data)
desc = parsed['description']
if desc.length > 120
desc = desc[0..120]
desc << "..."
end
result = {files: [], title: desc}
parsed['files'].each do |filename, attrs|
result[:files] << {filename: filename}.merge!(attrs)
end
result
end
end
end

View File

@ -1,49 +0,0 @@
require_dependency 'oneboxer/handlebars_onebox'
module Oneboxer
class GithubBlobOnebox < HandlebarsOnebox
matcher /^https?:\/\/(?:www\.)?github\.com\/[^\/]+\/[^\/]+\/blob\/.*/
favicon 'github.png'
def translate_url
m = @url.match(/github\.com\/(?<user>[^\/]+)\/(?<repo>[^\/]+)\/blob\/(?<sha1>[^\/]+)\/(?<file>[^#]+)(#(L(?<from>[^-]*)(-L(?<to>.*))?))?/mi)
if m
@from = (m[:from] || -1).to_i
@to = (m[:to] || -1).to_i
@file = m[:file]
return "https://raw.github.com/#{m[:user]}/#{m[:repo]}/#{m[:sha1]}/#{m[:file]}"
end
nil
end
def parse(data)
if @from > 0
if @to < 0
@from = @from - 10
@to = @from + 20
end
if @to > @from
data = data.split("\n")[@from..@to].join("\n")
end
end
extension = @file.split(".")[-1]
@lang = case extension
when "rb" then "ruby"
when "js" then "javascript"
else extension
end
truncated = false
if data.length > SiteSetting.onebox_max_chars
data = data[0..SiteSetting.onebox_max_chars-1]
truncated = true
end
{content: data, truncated: truncated}
end
end
end

View File

@ -1,24 +0,0 @@
require_dependency 'oneboxer/handlebars_onebox'
module Oneboxer
class GithubCommitOnebox < HandlebarsOnebox
matcher /^https?:\/\/(?:www\.)?github\.com\/[^\/]+\/[^\/]+\/commit\/.+/
favicon 'github.png'
def translate_url
m = @url.match(/github\.com\/(?<owner>[^\/]+)\/(?<repo>[^\/]+)\/commit\/(?<sha>[^\/]+)/mi)
return "https://api.github.com/repos/#{m[:owner]}/#{m[:repo]}/commits/#{m[:sha]}" if m.present?
@url
end
def parse(data)
result = JSON.parse(data)
result['commit_date'] = Time.parse(result['commit']['author']['date']).strftime("%I:%M%p - %d %b %y")
result
end
end
end

View File

@ -1,26 +0,0 @@
require_dependency 'oneboxer/handlebars_onebox'
module Oneboxer
class GithubPullrequestOnebox < HandlebarsOnebox
matcher /^https?:\/\/(?:www\.)?github\.com\/[^\/]+\/[^\/]+\/pull\/.+/
favicon 'github.png'
def translate_url
@url.match(
/github\.com\/(?<owner>[^\/]+)\/(?<repo>[^\/]+)\/pull\/(?<number>[^\/]+)/mi
) do |match|
"https://api.github.com/repos/#{match[:owner]}/#{match[:repo]}/pulls/#{match[:number]}"
end
end
def parse(data)
result = JSON.parse(data)
result['created_at'] =
Time.parse(result['created_at']).strftime("%I:%M%p - %d %b %y")
result
end
end
end

View File

@ -1,61 +0,0 @@
require 'open-uri'
require_dependency 'oneboxer/base_onebox'
module Oneboxer
class HandlebarsOnebox < BaseOnebox
unless defined? MAX_TEXT
MAX_TEXT = 500
end
def self.template_path(template_name)
"#{Rails.root}/lib/oneboxer/templates/#{template_name}.handlebars"
end
def template_path(template_name)
HandlebarsOnebox.template_path(template_name)
end
def template
template_name = self.class.name.underscore
template_name.gsub!(/oneboxer\//, '')
template_path(template_name)
end
def default_url
"<a href='#{@url}' target='_blank'>#{@url}</a>"
end
def http_params
{'User-Agent' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 5_0_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A405 Safari/7534.48.3'}
end
def fetch_html
open(translate_url, http_params).read
end
def onebox
html = fetch_html
args = parse(html)
return default_url unless args.present?
args[:original_url] = @url
args[:lang] = @lang || ""
args[:favicon] = ActionController::Base.helpers.asset_path(self.class.favicon_file, digest: false) if self.class.favicon_file.present?
args[:host] = nice_host
HandlebarsOnebox.generate_onebox(template,args)
rescue => ex
# If there's an exception, just embed the link
raise ex if Rails.env.development?
default_url
end
def self.generate_onebox(template, args={})
Mustache.render(File.read(template), args)
end
end
end

View File

@ -1,13 +0,0 @@
require_dependency 'oneboxer/oembed_onebox'
module Oneboxer
class HuluOnebox < OembedOnebox
matcher /^https?\:\/\/www\.hulu\.com\/watch\/.*$/
def oembed_endpoint
"http://www.hulu.com/api/oembed.json?url=#{BaseOnebox.uriencode(@url)}"
end
end
end

View File

@ -1,29 +0,0 @@
require 'open-uri'
require_dependency 'oneboxer/base_onebox'
module Oneboxer
class ImgurOnebox < BaseOnebox
matcher /^https?\:\/\/imgur\.com\/.*$/
def translate_url
m = @url.match(/\/gallery\/(?<hash>[^\/]+)/mi)
return "http://api.imgur.com/2/image/#{URI::encode(m[:hash])}.json" if m.present?
m = @url.match(/imgur\.com\/(?<hash>[^\/]+)/mi)
return "http://api.imgur.com/2/image/#{URI::encode(m[:hash])}.json" if m.present?
nil
end
def onebox
url = translate_url
return @url if url.blank?
parsed = JSON.parse(open(translate_url).read)
image = parsed['image']
BaseOnebox.image_html(image['links']['original'], image['image']['caption'], image['links']['imgur_page'])
end
end
end

View File

@ -1,14 +0,0 @@
require_dependency 'oneboxer/oembed_onebox'
module Oneboxer
class KinomapOnebox < OembedOnebox
matcher /^https?:\/\/(?:www\.)?kinomap\.com/
def oembed_endpoint
"http://www.kinomap.com/oembed?url=#{BaseOnebox.uriencode(@url)}&format=json"
end
end
end

View File

@ -1,14 +0,0 @@
require_dependency 'oneboxer/oembed_onebox'
module Oneboxer
class NfbOnebox < OembedOnebox
matcher /^https?:\/\/(?:www\.)?nfb\.ca\/film\/[-\w]+\/?/
def oembed_endpoint
"http://www.nfb.ca/remote/services/oembed/?url=#{BaseOnebox.uriencode(@url)}&format=json"
end
end
end

View File

@ -1,42 +0,0 @@
require 'open-uri'
require_dependency 'oneboxer/handlebars_onebox'
module Oneboxer
class OembedOnebox < HandlebarsOnebox
def oembed_endpoint
@url
end
def template
template_path('oembed_onebox')
end
def onebox
parsed = JSON.parse(open(oembed_endpoint).read)
# If it's a video, just embed the iframe
if %w(video rich).include?(parsed['type'])
# Return a preview of the thumbnail url, since iframes don't do well on previews
preview = nil
preview = "<img src='#{parsed['thumbnail_url']}'>" if parsed['thumbnail_url'].present?
return [parsed['html'], preview]
end
if %w(image photo).include?(parsed['type'])
return BaseOnebox.image_html(parsed['url'] || parsed['thumbnail_url'], parsed['title'], parsed['web_page'] || @url)
end
parsed['original_url'] = parsed['url']
parsed['html'] ||= parsed['abstract']
parsed['host'] = nice_host
Mustache.render(File.read(template), parsed)
rescue OpenURI::HTTPError
nil
end
end
end

View File

@ -1,29 +0,0 @@
require_dependency 'oneboxer/handlebars_onebox'
module Oneboxer
class OpenGraphOnebox < HandlebarsOnebox
def template
template_path('simple_onebox')
end
def onebox
# We expect to have the options we need already
return nil unless @opts.present?
# A site is supposed to supply all the basic og attributes, but some don't (like deviant art)
# If it just has image and no title, embed it as an image.
return BaseOnebox.image_html(@opts['image'], nil, @url) if @opts['image'].present? && @opts['title'].blank?
@opts['title'] ||= @opts['description']
return nil if @opts['title'].blank?
@opts[:original_url] = @url
@opts[:text] = @opts['description']
@opts[:unsafe] = true
@opts[:host] = nice_host
Mustache.render(File.read(template), @opts)
end
end
end

View File

@ -1,13 +0,0 @@
require_dependency 'oneboxer/oembed_onebox'
module Oneboxer
class QikOnebox < OembedOnebox
matcher /^https?\:\/\/qik\.com\/video\/.*$/
def oembed_endpoint
"http://qik.com/api/oembed.json?url=#{BaseOnebox.uriencode(@url)}"
end
end
end

View File

@ -1,13 +0,0 @@
require_dependency 'oneboxer/oembed_onebox'
module Oneboxer
class RevisionOnebox < OembedOnebox
matcher /^http\:\/\/(.*\.)?revision3\.com\/.*$/
def oembed_endpoint
"http://revision3.com/api/oembed/?url=#{BaseOnebox.uriencode(@url)}&format=json"
end
end
end

View File

@ -1,75 +0,0 @@
require_dependency 'oneboxer/handlebars_onebox'
module Oneboxer
class RottentomatoesOnebox < HandlebarsOnebox
# keep reloaders happy
unless defined? SYNOPSIS_MAX_TEXT
SYNOPSIS_MAX_TEXT = 370
ROTTEN_IMG = 'http://images.rottentomatoescdn.com/images/icons/rt.rotten.med.png'
FRESH_IMG = 'http://images.rottentomatoescdn.com/images/icons/rt.fresh.med.png'
POPCORN_IMG = 'http://images.rottentomatoescdn.com/images/icons/popcorn_27x31.png'
end
matcher /^http:\/\/(?:www\.)?rottentomatoes\.com(\/mobile)?\/m\/.*$/
favicon 'rottentomatoes.png'
def http_params
{'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31' }
end
def template
template_path('rottentomatoes_onebox')
end
def translate_url
m = @url.match(/^http:\/\/(?:www\.)?rottentomatoes\.com(\/mobile)?\/m\/(?<movie>.*)$/mi)
"http://rottentomatoes.com/mobile/m/#{m[:movie]}"
end
def parse(data)
html_doc = Nokogiri::HTML(data)
result = {}
result[:title] = html_doc.at('h1').content
result[:poster] = html_doc.at_css('.poster img')['src']
synopsis = html_doc.at_css('#movieSynopsis').content.squish
synopsis.gsub!(/\$\(function\(\).+$/, '')
result[:synopsis] = (synopsis.length > SYNOPSIS_MAX_TEXT ? "#{synopsis[0..SYNOPSIS_MAX_TEXT]}..." : synopsis)
result[:verdict_percentage], result[:user_percentage] = html_doc.css('.rtscores .rating .percentage span').map(&:content)
result[:popcorn_image] = POPCORN_IMG
if html_doc.at_css('.rtscores .rating .splat')
result[:verdict_image] = ROTTEN_IMG
elsif html_doc.at_css('.rtscores .rating .tomato')
result[:verdict_image] = FRESH_IMG
end
result[:cast] = html_doc.css('.summary .actors a').map(&:content).join(", ")
html_doc.css('#movieInfo .info').map(&:inner_html).each do |element|
case
when element.include?('Director:') then result[:director] = clean_up_info(element)
when element.include?('Rated:') then result[:rated] = clean_up_info(element)
when element.include?('Running Time:') then result[:running_time] = clean_up_info(element)
when element.include?('DVD Release:')
result[:release_date] = clean_up_info(element)
result[:release_type] = 'DVD'
# Only show the theater release date if there is no DVD release date
when element.include?('Theater Release:') && !result[:release_type]
result[:release_date] = clean_up_info(element)
result[:release_type] = 'Theater'
end
end
result.delete_if { |k, v| v.blank? }
end
def clean_up_info(inner_html)
inner_html.squish.gsub(/^.*<\/span>\s*/, '')
end
end
end

View File

@ -1,14 +0,0 @@
require_dependency 'oneboxer/oembed_onebox'
module Oneboxer
class SlideshareOnebox < OembedOnebox
matcher /^https?\:\/\/(www\.)?slideshare\.net\/*\/.*$/
def oembed_endpoint
"http://www.slideshare.net/api/oembed/2?url=#{BaseOnebox.uriencode(@url)}&format=json&maxwidth=600"
end
end
end

View File

@ -1,13 +0,0 @@
require_dependency 'oneboxer/oembed_onebox'
module Oneboxer
class SmugmugOnebox < OembedOnebox
matcher /^https?\:\/\/.*\.smugmug\.com\/.*$/
def oembed_endpoint
"http://api.smugmug.com/services/oembed/?url=#{BaseOnebox.uriencode(@url)}&format=json"
end
end
end

View File

@ -1,10 +0,0 @@
require_dependency 'oneboxer/oembed_onebox'
module Oneboxer
class SoundcloudOnebox < OembedOnebox
matcher /^https?:\/\/(?:www\.)?soundcloud\.com\/.+$/
def oembed_endpoint
"http://soundcloud.com/oembed?url=#{BaseOnebox.uriencode(@url.sub('https://', 'http://'))}&format=json"
end
end
end

View File

@ -1,52 +0,0 @@
require_dependency 'oneboxer/handlebars_onebox'
module Oneboxer
class StackExchangeOnebox < HandlebarsOnebox
unless defined? DOMAINS
DOMAINS = [
'stackexchange',
'stackoverflow',
'superuser',
'serverfault',
'askubuntu'
]
end
# http://rubular.com/r/V3T0I1VTPn
unless defined? REGEX
REGEX = /^http:\/\/(?:(?:(?<subsubdomain>\w*)\.)?(?<subdomain>\w*)\.)?(?<domain>#{DOMAINS.join('|')})\.com\/(?:questions|q)\/(?<question>\d*)/
end
matcher REGEX
favicon 'stackexchange.png'
def translate_url
@url.match(REGEX) do |match|
site = if match[:domain] == 'stackexchange'
[match[:subsubdomain],match[:subdomain]].compact.join('.')
else
[match[:subdomain],match[:domain]].compact.join('.')
end
["http://api.stackexchange.com/2.1/",
"questions/#{match[:question]}",
"?site=#{site}"
].join
end
end
def parse(data)
result = JSON.parse(data)['items'].first
if result
result['creation_date'] =
Time.at(result['creation_date'].to_i).strftime("%I:%M%p - %d %b %y")
result['tags'] = result['tags'].take(4).join(', ')
end
result
end
end
end

View File

@ -1,10 +0,0 @@
require_dependency 'oneboxer/oembed_onebox'
module Oneboxer
class TedOnebox < OembedOnebox
matcher /^https?\:\/\/(www\.)?ted\.com\/talks\/.*$/
def oembed_endpoint
"http://www.ted.com/talks/oembed.json?url=#{BaseOnebox.uriencode(@url)}"
end
end
end

View File

@ -1,20 +0,0 @@
<aside class='quote' data-post="1" data-topic="{{topic}}">
<div class='title'>
<div class='quote-controls'></div>
{{{avatar}}}
<a href="{{original_url}}">{{title}}</a> {{{category}}}
</div>
<blockquote>{{{quote}}}
<div class='topic-info'>
<div class='info-line'>
{{posts_count}} posts, last post {{last_post}}, created {{age}}, {{views}} views
</div>
<div class='posters'>
{{#posters}}
{{{avatar}}}
{{/posters}}
</div>
<div class='clearfix'></div>
</div>
</blockquote>
</aside>

View File

@ -1,8 +0,0 @@
<div class='onebox-result'>
{{{avatar}}}
<h3><a href="{{original_url}}">{{username}}</a></h3>
{{#bio}}<p>{{bio}}</p>{{/bio}}
<div class='clearfix'></div>
</div>

View File

@ -1,16 +0,0 @@
<div class='onebox-result'>
{{#host}}
<a href='{{original_url}}' class='source track-link' target="_blank">
{{#favicon}}<img class='favicon' src="{{favicon}}"> {{/favicon}}{{host}}
</a>
{{/host}}
<div class='onebox-result-body'>
{{#title}}
<h3><a href="{{original_url}}" target="_blank">{{title}}</a></h3>
{{/title}}
{{#files}}
<h4>{{filename}}</h4>
<pre><code>{{content}}</code></pre>
{{/files}}
</div>
</div>

View File

@ -1,19 +0,0 @@
<div class='onebox-result'>
{{#host}}
<div class="source">
<div class="info">
<a href='{{original_url}}' class='source track-link' target="_blank">
{{#favicon}}<img class='favicon' src="{{favicon}}"> {{/favicon}}{{host}}
</a>
</div>
</div>
{{/host}}
<div class='onebox-result-body'>
<h4><a href="{{original_url}}" target="_blank">{{original_url}}</a></h4>
<pre><code class='{{lang}}'>{{content}}</code></pre>
{{#truncated}}
This file has been truncated. <a href="{{original_url}}" target="_blank">show original</a>
{{/truncated}}
</div>
</div>

View File

@ -1,38 +0,0 @@
<div class="onebox-result">
{{#host}}
<div class="source">
<div class="info">
<a href="{{html_url}}" class="track-link" target="_blank">
{{#favicon}}
<img class="favicon" src="{{favicon}}">
{{/favicon}}
{{host}}
</a>
</div>
</div>
{{/host}}
<div class="onebox-result-body">
{{#author.avatar_url}}
<a href="{{author.html_url}}" target="_blank">
<img alt="{{author.login}}" src="{{author.avatar_url}}">
</a>
{{/author.avatar_url}}
<h4>
<a href="{{html_url}}" target="_blank">{{commit.message}}</a>
</h4>
<div class="date">
by <a href="{{author.html_url}}" target="_blank">{{author.login}}</a>
on <a href="{{html_url}}" target="_blank">{{commit_date}}</a>
</div>
<div class="github-commit-stats">
changed <strong>{{files.length}} files</strong>
with <strong>{{stats.additions}} additions</strong>
and <strong>{{stats.deletions}} deletions</strong>.
</div>
</div>
<div class="clearfix"></div>
</div>

View File

@ -1,39 +0,0 @@
<div class="onebox-result">
{{#host}}
<div class="source">
<div class="info">
<a href="{{html_url}}" class="track-link" target="_blank">
{{#favicon}}
<img class="favicon" src="{{favicon}}">
{{/favicon}}
{{host}}
</a>
</div>
</div>
{{/host}}
<div class="onebox-result-body">
{{#user.avatar_url}}
<a href="{{user.html_url}}" target="_blank">
<img alt="{{user.login}}" src="{{user.avatar_url}}">
</a>
{{/user.avatar_url}}
<h4>
<a href="{{html_url}}" target="_blank">{{title}}</a>
</h4>
<div class="date">
by <a href="{{user.html_url}}" target="_blank">{{user.login}}</a>
on <a href="{{html_url}}" target="_blank">{{created_at}}</a>
</div>
<div class="github-commit-stats">
<strong>{{commits}} commits</strong>
changed <strong>{{changed_files}} files</strong>
with <strong>{{additions}} additions</strong>
and <strong>{{deletions}} deletions</strong>.
</div>
</div>
<div class="clearfix"></div>
</div>

View File

@ -1,17 +0,0 @@
<div class='onebox-result'>
{{#host}}
<div class="source">
<div class="info">
<a href='{{original_url}}' class='source track-link' target="_blank">
{{#favicon}}<img class='favicon' src="{{favicon}}"> {{/favicon}}{{host}}
</a>
</div>
</div>
{{/host}}
<div class='onebox-result-body'>
<h3><a href="{{original_url}}" target="_blank">{{title}}</a></h3>
{{#author_info}}<h4>{{author_info}}</h4>{{/author_info}}
{{{html}}}
</div>
<div class='clearfix'></div>
</div>

View File

@ -1,25 +0,0 @@
<div class='onebox-result'>
{{#host}}
<div class='source'>
<div class='info'>
<a href='{{original_url}}' class="track-link" target="_blank">
{{#favicon}}<img class='favicon' src="{{favicon}}"> {{/favicon}}{{host}}
</a>
</div>
</div>
{{/host}}
<div class='onebox-result-body'>
{{#poster}}<img src="{{poster}}" class="thumbnail">{{/poster}}
<h3><a href="{{original_url}}" target="_blank">{{title}}</a></h3>
{{#verdict_image}}<img class="verdict" src={{verdict_image}}><b>{{verdict_percentage}}</b> of critics liked it.{{/verdict_image}}
{{#user_percentage}}<img class="popcorn" src={{popcorn_image}}><b>{{user_percentage}}</b> of users liked it.<br />{{/user_percentage}}
{{#cast}}<b>Cast:</b> {{cast}}<br />{{/cast}}
{{#director}}<b>Director:</b> {{director}}<br />{{/director}}
{{#release_type}}<b>{{release_type}} Release:</b> {{release_date}}<br />{{/release_type}}
{{#running_time}}<b>Running Time:</b> {{running_time}}<br />{{/running_time}}
{{#rated}}<b>Rated: </b> {{rated}}<br />{{/rated}}
{{synopsis}}
</div>
<div class='clearfix'></div>
</div>

View File

@ -1,23 +0,0 @@
<div class='onebox-result'>
{{#host}}
<div class='source'>
<div class='info'>
<a href='{{original_url}}' class="track-link" target="_blank">
{{#favicon}}<img class='favicon' src="{{favicon}}"> {{/favicon}}{{host}}
</a>
</div>
</div>
{{/host}}
<div class='onebox-result-body'>
{{#image}}<img src="{{image}}" class="thumbnail">{{/image}}
<h3><a href="{{original_url}}" target="_blank"{{#image_height}} height="{{image_height}}"{{/image_height}}{{#image_width}} width="{{image_width}}"{{/image_width}}>{{title}}</a></h3>
{{#by_info}}<h4>{{by_info}}</h4>{{/by_info}}
{{#unsafe}}
{{text}}
{{/unsafe}}
{{^unsafe}}
{{{text}}}
{{/unsafe}}
</div>
<div class='clearfix'></div>
</div>

View File

@ -1,38 +0,0 @@
<div class="onebox-result">
{{#host}}
<div class="source">
<div class="info">
<a href="{{link}}" class="track-link" target="_blank">
{{#favicon}}
<img class="favicon" src="{{favicon}}">
{{/favicon}}
{{host}}
</a>
</div>
</div>
{{/host}}
<div class="onebox-result-body">
{{#owner.profile_image}}
<a href="{{owner.link}}" target="_blank">
<img alt="{{owner.display_name}}" src="{{owner.profile_image}}">
</a>
{{/owner.profile_image}}
<h4>
<a href="{{link}}" target="_blank">{{{title}}}</a>
</h4>
<div class="date">
asked by <a href="{{owner.link}}" target="_blank">
{{owner.display_name}}
</a>
on <a href="{{link}}" target="_blank">{{creation_date}}</a>
</div>
<div>
<strong>{{tags}}</strong>
</div>
</div>
<div class="clearfix"></div>
</div>

View File

@ -1,28 +0,0 @@
<div class='onebox-result'>
{{#host}}
<div class="source">
<div class="info">
<a href='{{original_url}}' class="track-link" target="_blank">
{{#favicon}}<img class='favicon' src="{{favicon}}"> {{/favicon}}{{host}}
</a>
</div>
</div>
{{/host}}
<div class='onebox-result-body'>
{{#user.profile_image_url}}
<img src="{{user.profile_image_url}}">{{/user.profile_image_url}}
<h4>
<a href='https://twitter.com/{{user.screen_name}}'>
@{{user.screen_name}}
</a>
</h4>
{{{text}}}
<div class='date'>
<a href="{{original_url}}" target="_blank">{{created_at}}</a>
</div>
</div>
<div class='clearfix'></div>
</div>

View File

@ -1,39 +0,0 @@
require_dependency 'oneboxer/handlebars_onebox'
require_dependency 'twitter_api'
module Oneboxer
class TwitterOnebox < HandlebarsOnebox
unless defined? BASE_URL
BASE_URL = 'https://api.twitter.com'.freeze
end
unless defined? REGEX
REGEX = /^https?:\/\/(?:www\.)?twitter.com\/(?<user>[^\/]+)\/status\/(?<id>\d+)$/
end
matcher REGEX
# TODO: use zocial instead
favicon 'twitter.png'
def fetch_html
raise Discourse::SiteSettingMissing if TwitterApi.twitter_credentials_missing?
# a bit odd, but I think the api expects html
TwitterApi.raw_tweet_for(@url.match(REGEX)[:id])
end
def parse(data)
result = JSON.parse(data)
result['created_at'] =
Time.parse(result['created_at']).strftime("%I:%M%p - %d %b %y")
result['text'] = TwitterApi.prettify_tweet(result)
result
end
end
end

View File

@ -1,13 +0,0 @@
require_dependency 'oneboxer/oembed_onebox'
module Oneboxer
class ViddlerOnebox < OembedOnebox
matcher /^https?:\/\/(?:www\.)?viddler\.com\/.+$/
def oembed_endpoint
"http://lab.viddler.com/services/oembed/?url=#{BaseOnebox.uriencode(@url)}"
end
end
end

View File

@ -1,13 +0,0 @@
require_dependency 'oneboxer/oembed_onebox'
module Oneboxer
class VimeoOnebox < OembedOnebox
matcher /^https?\:\/\/vimeo\.com\/.*$/
def oembed_endpoint
"http://vimeo.com/api/oembed.json?url=#{BaseOnebox.uriencode(@url)}&width=600"
end
end
end

View File

@ -1,124 +0,0 @@
#******************************************************************************#
# #
# Oneboxer already supports most sites using OpenGraph via the OpenGraphOnebox #
# class. If the site you want to create a onebox for supports OpenGraph, #
# please try adding the site to the whitelist below before creating a custom #
# parser or template. #
# #
#******************************************************************************#
module Oneboxer
module Whitelist
def self.entries
@entries ||= [
Entry.new(/^https?:\/\/(?:www\.)?findery\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?zappos\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?slideshare\.net\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?rottentomatoes\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?cnn\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?washingtonpost\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?funnyordie\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?500px\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?scribd\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?photobucket\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?ebay\.(com|ca|co\.uk)\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?nytimes\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?pinterest\.com\/.+/),
# Entry.new(/^https?:\/\/(?:www\.)?imdb\.com\/.+/), # For legal reasons, we cannot include IMDB onebox support
Entry.new(/^https?:\/\/(?:www\.)?bbc\.co\.uk\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?ask\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?huffingtonpost\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?aol\.(com|ca)\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?espn\.go\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?about\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?cnet\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?ehow\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?dailymail\.co\.uk\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?indiatimes\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?answers\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?instagr\.am\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?battle\.net\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?sourceforge\.net\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?myspace\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?wikia\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?etsy\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?walmart\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?reference\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?yelp\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?foxnews\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?guardian\.co\.uk\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?digg\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?squidoo\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?wsj\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?archive\.org\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?nba\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?samsung\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?mashable\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?forbes\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?thefreedictionary\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?groupon\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?ikea\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?dell\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?mlb\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?bestbuy\.(com|ca)\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?bloomberg\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?ign\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?twitpic\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?techcrunch\.com\/.+/, false),
Entry.new(/^https?:\/\/(?:www\.)?usatoday\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?go\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?businessinsider\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?zillow\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?tmz\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?thesun\.co\.uk\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?thestar\.(com|ca)\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?theglobeandmail\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?torontosun\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?kickstarter\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?wired\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?time\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?npr\.org\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?cracked\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?deadline\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?thinkgeek\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?theonion\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?screenr\.com\/.+/),
Entry.new(/^https?:\/\/(?:www\.)?tumblr\.com\/.+/, false),
Entry.new(/^https?:\/\/(?:www\.)?howtogeek\.com\/.+/, false),
Entry.new(/^https?:\/\/(?:www\.)?screencast\.com\/.+/),
Entry.new(/\/\d{4}\/\d{2}\/\d{2}\//, false), # wordpress
Entry.new(/^https?:\/\/[^\/]+\/t\/[^\/]+\/\d+(\/\d+)?(\?.*)?$/),
# Online learning resources
Entry.new(/^https?:\/\/(?:www\.)?coursera\.org\/.+/, false),
Entry.new(/^https?:\/\/(?:www\.)?khanacademy\.org\/.+/, false),
Entry.new(/^https?:\/\/(?:www\.)?ted\.com\/talks\/.+/, false), # only /talks have meta info
Entry.new(/^https?:\/\/(?:www\.)?wikihow\.com\/.+/, false),
Entry.new(/^https?:\/\/(?:\w+\.)?wonderhowto\.com\/.+/, false)
]
end
def self.entry_for_url(url)
entries.each {|e| return e if e.matches?(url) }
nil
end
class Entry
# oembed = false is probably safer, but this is the least-drastic change
def initialize(pattern, oembed = true)
@pattern = pattern
@oembed = oembed
end
def allows_oembed?
@oembed
end
def matches?(url)
url =~ @pattern
end
end
end
end

View File

@ -1,58 +0,0 @@
require_dependency 'oneboxer/handlebars_onebox'
module Oneboxer
class WikipediaOnebox < HandlebarsOnebox
matcher /^https?:\/\/.*wikipedia\.(com|org)\/.*$/
favicon 'wikipedia.png'
def template
template_path('simple_onebox')
end
def translate_url
m = @url.match(/^https?:\/\/((?<subdomain>.+)\.)?wikipedia\.(com|org)\/wiki\/(?<identifier>[^#\/]+)/mi)
subdomain = m[:subdomain] || "en"
article_id = CGI::unescape(m[:identifier])
"http://#{subdomain}.m.wikipedia.org/w/index.php?title=#{URI::encode(article_id)}"
end
def parse(data)
html_doc = Nokogiri::HTML(data)
result = {}
title = html_doc.at('title').inner_html
result[:title] = title.gsub!(/ - Wikipedia.*$/, '') if title.present?
# get the first image > 150 pix high
images = html_doc.search("img").select { |img| img['height'].to_i > 150 }
result[:image] = "http:#{images[0]["src"]}" unless images.empty?
# remove the table from mobile layout, as it can contain paras in some rare cases
html_doc.search("table").remove
# get all the paras
paras = html_doc.search("p")
text = ""
unless paras.empty?
cnt = 0
while text.length < MAX_TEXT && cnt <= 3
text << " " unless cnt == 0
paragraph = paras[cnt].inner_text[0..MAX_TEXT]
paragraph.gsub!(/\[\d+\]/mi, "")
text << paragraph
cnt += 1
end
end
text = "#{text[0..MAX_TEXT]}..." if text.length > MAX_TEXT
result[:text] = text
result
end
end
end

View File

@ -1,13 +0,0 @@
require_dependency 'oneboxer/oembed_onebox'
module Oneboxer
class YfrogOnebox < OembedOnebox
matcher /^https?:\/\/(?:www\.)?yfrog\.(com|ru|com\.tr|it|fr|co\.il|co\.uk|com\.pl|pl|eu|us)\/[a-zA-Z0-9]+/
def oembed_endpoint
"http://www.yfrog.com/api/oembed/?url=#{BaseOnebox.uriencode(@url)}&format=json"
end
end
end

View File

@ -1,20 +0,0 @@
require_dependency 'oneboxer/oembed_onebox'
module Oneboxer
class YoutubeOnebox < OembedOnebox
matcher /^https?:\/\/(?:www\.)?(?:youtube\.com|youtu\.be)\/.+$/
def oembed_endpoint
"http://www.youtube.com/oembed?url=#{BaseOnebox.uriencode(@url.sub('https://', 'http://'))}&format=json"
end
def onebox
(super || []).each do |entry|
# Youtube allows HTTP and HTTPS, so replace them with the protocol-agnostic variant
BaseOnebox.replace_agnostic entry
# Add wmode=opaque to the iframe src URL so that the flash player is rendered within the document flow instead of on top
BaseOnebox.append_embed_wmode entry
end
end
end
end

View File

@ -1,42 +0,0 @@
# encoding: utf-8
require 'spec_helper'
require 'oneboxer'
require 'oneboxer/amazon_onebox'
describe Oneboxer::AmazonOnebox do
before(:each) do
@o = Oneboxer::AmazonOnebox.new("http://www.amazon.com/Ruby-Programming-Language-David-Flanagan/dp/0596516177")
FakeWeb.register_uri(:get, @o.translate_url, response: fixture_file('oneboxer/amazon.response'))
end
it "translates the URL" do
@o.translate_url.should == "http://www.amazon.com/gp/aw/d/0596516177"
end
it "generates the expected onebox for Amazon" do
@o.onebox.should match_html expected_amazon_result
end
private
def expected_amazon_result
<<EXPECTED
<div class='onebox-result'>
<div class='source'>
<div class='info'>
<a href='http://www.amazon.com/Ruby-Programming-Language-David-Flanagan/dp/0596516177' class="track-link" target="_blank">
<img class='favicon' src="/assets/favicons/amazon.png"> amazon.com
</a>
</div>
</div>
<div class='onebox-result-body'>
<img src="http://ecx.images-amazon.com/images/I/512Cx%2BnJK8L._BO2,204,203,200_PIsitb-sticker-arrow-click,TopRight,35,-76_AA300_SH20_OU01_.jpg" class="thumbnail">
<h3><a href="http://www.amazon.com/Ruby-Programming-Language-David-Flanagan/dp/0596516177" target="_blank">The Ruby Programming Language [Paperback]</a></h3>
</div>
<div class='clearfix'></div>
</div>
EXPECTED
end
end

View File

@ -1,41 +0,0 @@
# encoding: utf-8
require 'spec_helper'
require 'oneboxer'
require 'oneboxer/android_app_store_onebox'
describe Oneboxer::AndroidAppStoreOnebox do
before(:each) do
@o = Oneboxer::AndroidAppStoreOnebox.new("https://play.google.com/store/apps/details?id=com.moosoft.parrot")
FakeWeb.register_uri(:get, @o.translate_url, response: fixture_file('oneboxer/android.response'))
end
it "generates the expected onebox for Android App Store" do
@o.onebox.should match_html expected_android_app_store_result
end
private
def expected_android_app_store_result
<<EXPECTED
<div class='onebox-result'>
<div class='source'>
<div class='info'>
<a href='https://play.google.com/store/apps/details?id=com.moosoft.parrot' class="track-link" target="_blank">
<img class='favicon' src="/assets/favicons/google_play.png"> play.google.com
</a>
</div>
</div>
<div class='onebox-result-body'>
<img src="https://lh5.ggpht.com/wrYYVu74XNUu2WHk0aSZEqgdCDCNti9Fl0_dJnhgR6jY04ajQgVg5ABMatfcTDsB810=w124" class="thumbnail">
<h3><a href="https://play.google.com/store/apps/details?id=com.moosoft.parrot" target="_blank">Talking Parrot</a></h3>
Listen to the parrot repeat what you say. A Fun application for all ages. Upgrade to Talking Parrot Pro to save sounds, set them as your ringtone and control recording.
Press the MENU button to access the settings where you can change the record time and repeat count.
This app uses anonymous usage stats to understand and improve performance.
Comments and feedback welcome.
</div>
<div class='clearfix'></div>
</div>
EXPECTED
end
end

View File

@ -1,38 +0,0 @@
# encoding: utf-8
require 'spec_helper'
require 'oneboxer'
require 'oneboxer/apple_app_onebox'
describe Oneboxer::AppleAppOnebox do
before(:each) do
@o = Oneboxer::AppleAppOnebox.new("https://itunes.apple.com/us/app/minecraft-pocket-edition-lite/id479651754")
FakeWeb.register_uri(:get, @o.translate_url, response: fixture_file('oneboxer/apple.response'))
end
it "generates the expected onebox for Apple app" do
@o.onebox.should match_html expected_apple_app_result
end
private
def expected_apple_app_result
<<EXPECTED
<div class='onebox-result'>
<div class='source'>
<div class='info'>
<a href='https://itunes.apple.com/us/app/minecraft-pocket-edition-lite/id479651754' class="track-link" target="_blank">
<img class='favicon' src="/assets/favicons/apple.png"> itunes.apple.com
</a>
</div>
</div>
<div class='onebox-result-body'>
<img src="http://a5.mzstatic.com/us/r1000/087/Purple/99/2f/dd/mzl.erzwvjsi.175x175-75.jpg" class="thumbnail">
<h3><a href="https://itunes.apple.com/us/app/minecraft-pocket-edition-lite/id479651754" target="_blank">Minecraft Pocket Edition Lite</a></h3>
Imagine it, build it. Create worlds on the go with Minecraft - Pocket EditionThis is the Lite version of Minecraft - Pocket Edition. Minecraft - Pocket Edition allows you to build on the go. Use blocks to create masterpieces as you travel, hangout with friends, sit at the park, the possibilities are endless. Move beyond the limits of your computer and play Minecraft everywhere you go.Limitations of the Lite version* The world is not saved between sessions* Multiplayer worlds can not be copied to
</div>
<div class='clearfix'></div>
</div>
EXPECTED
end
end

View File

@ -1,33 +0,0 @@
require 'spec_helper'
require 'oneboxer'
require 'oneboxer/_flash_video_onebox'
describe Oneboxer::FlashVideoOnebox do
before do
@o = Oneboxer::FlashVideoOnebox.new('http://player.56.com/v_OTMyNTk1MzE.swf')
end
context "when SiteSetting.enable_flash_video_onebox is true" do
before do
SiteSetting.stubs(:enable_flash_video_onebox).returns(true)
end
it "generates a flash video" do
expect(@o.onebox).to match_html(
"<object width='100%' height='100%' wmode='opaque'><param name='http://player.56.com/v_OTMyNTk1MzE.swf' value='http://player.56.com/v_OTMyNTk1MzE.swf'><embed src='http://player.56.com/v_OTMyNTk1MzE.swf' width='100%' height='100%' wmode='opaque'></embed></object>"
)
end
end
context "when SiteSetting.enable_flash_video_onebox is false" do
before do
SiteSetting.stubs(:enable_flash_video_onebox).returns(false)
end
it "generates a link" do
expect(@o.onebox).to match_html(
"<a href='http://player.56.com/v_OTMyNTk1MzE.swf'>http://player.56.com/v_OTMyNTk1MzE.swf</a>"
)
end
end
end

View File

@ -1,21 +0,0 @@
# encoding: utf-8
require 'spec_helper'
require 'oneboxer'
require 'oneboxer/flickr_onebox'
describe Oneboxer::FlickrOnebox do
before(:each) do
@o = Oneboxer::FlickrOnebox.new("http://www.flickr.com/photos/jaimeiniesta/3303881265")
FakeWeb.register_uri(:get, @o.translate_url, response: fixture_file('oneboxer/flickr.response'))
end
it "generates the expected onebox for Flickr" do
@o.onebox.should match_html expected_flickr_result
end
private
def expected_flickr_result
"<a href='http://www.flickr.com/photos/jaimeiniesta/3303881265' target='_blank'><img src='http://farm4.staticflickr.com/3419/3303881265_c6924748e8_z.jpg' alt=''></a>"
end
end

View File

@ -1,16 +0,0 @@
require 'spec_helper'
require 'oneboxer'
require 'oneboxer/gist_onebox'
describe Oneboxer::GistOnebox do
it "does not trip on user names" do
o = Oneboxer::GistOnebox.new('https://gist.github.com/aaa/4599619')
o.translate_url.should == 'https://api.github.com/gists/4599619'
end
it "works for old school urls too" do
o = Oneboxer::GistOnebox.new('https://gist.github.com/4599619')
o.translate_url.should == 'https://api.github.com/gists/4599619'
end
end

View File

@ -1,16 +0,0 @@
# encoding: utf-8
require 'spec_helper'
require 'oneboxer'
require 'oneboxer/github_commit_onebox'
describe Oneboxer::GithubCommitOnebox do
before(:each) do
@o = Oneboxer::GithubCommitOnebox.new("https://github.com/discourse/discourse/commit/ee76f1926defa8309b3a7ea64a25707519529a13")
FakeWeb.register_uri(:get, @o.translate_url, response: fixture_file('oneboxer/github_commit_onebox.response'))
end
it "translates the URL" do
@o.translate_url.should == "https://api.github.com/repos/discourse/discourse/commits/ee76f1926defa8309b3a7ea64a25707519529a13"
end
end

View File

@ -1,17 +0,0 @@
require 'spec_helper'
require 'oneboxer'
require 'oneboxer/github_pullrequest_onebox'
describe Oneboxer::GithubPullrequestOnebox do
describe '#translate_url' do
it 'returns the api url for the given pull request' do
onebox = described_class.new(
'https://github.com/discourse/discourse/pull/988'
)
expect(onebox.translate_url).to eq(
'https://api.github.com/repos/discourse/discourse/pulls/988'
)
end
end
end

View File

@ -1,35 +0,0 @@
require 'spec_helper'
require 'oneboxer'
require 'oneboxer/handlebars_onebox'
describe Oneboxer::HandlebarsOnebox do
describe 'simple onebox' do
H = Oneboxer::HandlebarsOnebox
it "is able to render image size when specified" do
template = H.template_path('simple_onebox')
result = H.generate_onebox(template, 'image_width' => 100, 'image_height' => 100, image: 'http://my.com/image.png')
result.should =~ /width=/
result.should =~ /height=/
end
class SimpleOnebox < Oneboxer::HandlebarsOnebox
favicon 'stackexchange.png'
def parse(html)
{ testing: true }
end
end
it "does not use fingerprint on favicons" do
onebox = SimpleOnebox.new "http://domain.com"
onebox.stubs(:fetch_html).returns("")
ActionController::Base.helpers.expects(:asset_path).with('favicons/stackexchange.png', digest: false)
result = onebox.onebox
end
end
end

View File

@ -1,115 +0,0 @@
# encoding: utf-8
require 'spec_helper'
require 'oneboxer'
require 'oneboxer/rottentomatoes_onebox'
describe Oneboxer::RottentomatoesOnebox do
it 'translates the URL' do
o = Oneboxer::RottentomatoesOnebox.new('http://www.rottentomatoes.com/m/mud_2012/')
expect(o.translate_url).to eq('http://rottentomatoes.com/mobile/m/mud_2012/')
end
it 'generates the expected onebox for a fresh movie' do
o = Oneboxer::RottentomatoesOnebox.new('http://www.rottentomatoes.com/m/mud_2012/')
FakeWeb.register_uri(:get, o.translate_url, response: fixture_file('oneboxer/rottentomatoes_fresh.response'))
o.onebox.should match_html expected_fresh_result
end
it 'generates the expected onebox for a rotten movie' do
o = Oneboxer::RottentomatoesOnebox.new('http://www.rottentomatoes.com/m/the_big_wedding_2013/')
FakeWeb.register_uri(:get, o.translate_url, response: fixture_file('oneboxer/rottentomatoes_rotten.response'))
o.onebox.should match_html expected_rotten_result
end
it 'generates the expected onebox for a movie with an incomplete description' do
o = Oneboxer::RottentomatoesOnebox.new('http://www.rottentomatoes.com/m/gunde_jaari_gallanthayyinde/')
FakeWeb.register_uri(:get, o.translate_url, response: fixture_file('oneboxer/rottentomatoes_incomplete.response'))
o.onebox.should match_html expected_incomplete_result
end
private
def expected_fresh_result
<<EXPECTED
<div class='onebox-result'>
<div class='source'>
<div class='info'>
<a href='http://www.rottentomatoes.com/m/mud_2012/' class="track-link" target="_blank">
<img class='favicon' src="/assets/favicons/rottentomatoes.png"> rottentomatoes.com
</a>
</div>
</div>
<div class='onebox-result-body'>
<img src="http://content7.flixster.com/movie/11/16/93/11169361_pro.jpg" class="thumbnail">
<h3><a href="http://www.rottentomatoes.com/m/mud_2012/" target="_blank">Mud</a></h3>
<img class="verdict" src=http://images.rottentomatoescdn.com/images/icons/rt.fresh.med.png><b>98%</b> of critics liked it.
<img class="popcorn" src=http://images.rottentomatoescdn.com/images/icons/popcorn_27x31.png><b>85%</b> of users liked it.<br />
<b>Cast:</b> Matthew McConaughey, Reese Witherspoon<br />
<b>Director:</b> Jeff Nichols<br />
<b>Theater Release:</b> Apr 26, 2013<br />
<b>Running Time:</b> 2 hr. 10 min.<br />
<b>Rated: </b> PG-13<br />
Mud is an adventure about two boys, Ellis and his friend Neckbone, who find a man named Mud hiding out on an island in the Mississippi. Mud describes fantastic scenarios-he killed a man in Texas and vengeful bounty hunters are coming to get him. He says he is planning to meet and escape with the love of his life, Juniper, who is waiting for him in town. Skeptical but i...
</div>
<div class='clearfix'></div>
</div>
EXPECTED
end
def expected_rotten_result
<<EXPECTED
<div class='onebox-result'>
<div class='source'>
<div class='info'>
<a href='http://www.rottentomatoes.com/m/the_big_wedding_2013/' class="track-link" target="_blank">
<img class='favicon' src="/assets/favicons/rottentomatoes.png"> rottentomatoes.com
</a>
</div>
</div>
<div class='onebox-result-body'>
<img src="http://content8.flixster.com/movie/11/16/87/11168754_pro.jpg" class="thumbnail">
<h3><a href="http://www.rottentomatoes.com/m/the_big_wedding_2013/" target="_blank">The Big Wedding</a></h3>
<img class="verdict" src=http://images.rottentomatoescdn.com/images/icons/rt.rotten.med.png><b>6%</b> of critics liked it.
<img class="popcorn" src=http://images.rottentomatoescdn.com/images/icons/popcorn_27x31.png><b>80%</b> of users liked it.<br />
<b>Cast:</b> Robert De Niro, Diane Keaton<br />
<b>Director:</b> Justin Zackham<br />
<b>Theater Release:</b> Apr 26, 2013<br />
<b>Running Time:</b> 1 hr. 29 min.<br />
<b>Rated: </b> R<br />
With an all-star cast led by Robert De Niro, Katherine Heigl, Diane Keaton, Amanda Seyfried, Topher Grace, with Susan Sarandon and Robin Williams, THE BIG WEDDING is an uproarious romantic comedy about a charmingly modern family trying to survive a weekend wedding celebration that has the potential to become a full blown family fiasco. To the amusement of their adult c...
</div>
<div class='clearfix'></div>
</div>
EXPECTED
end
def expected_incomplete_result
<<EXPECTED
<div class='onebox-result'>
<div class='source'>
<div class='info'>
<a href='http://www.rottentomatoes.com/m/gunde_jaari_gallanthayyinde/' class="track-link" target="_blank">
<img class='favicon' src="/assets/favicons/rottentomatoes.png"> rottentomatoes.com
</a>
</div>
</div>
<div class='onebox-result-body'>
<img src="http://images.rottentomatoescdn.com/images/redesign/poster_default.gif" class="thumbnail">
<h3><a href="http://www.rottentomatoes.com/m/gunde_jaari_gallanthayyinde/" target="_blank">Gunde Jaari Gallanthayyinde</a></h3>
<b>Cast:</b> Nithin, Nithya Menon<br />
<b>Director:</b> Vijay Kumar Konda<br />
<b>Theater Release:</b> Apr 19, 2013<br />
<b>Running Time:</b> 2 hr. 35 min.<br />
<b>Rated: </b> Unrated<br />
Software engineer Karthik thinks he is the smartest guy on the earth, but he turns out be the biggest fool at the end.
</div>
<div class='clearfix'></div>
</div>
EXPECTED
end
end

View File

@ -1,73 +0,0 @@
require 'spec_helper'
describe Oneboxer::StackExchangeOnebox do
describe '#translate_url' do
let(:question) { '15622543' }
let(:api_url) {
"http://api.stackexchange.com/2.1/questions/#{question}?site=#{site}"
}
context 'when the question is from Stack Overflow' do
let(:site) { 'stackoverflow' }
it 'returns the correct api url for an expanded url' do
onebox = described_class.new([
"http://#{site}.com/",
"questions/#{question}/discourse-ruby-2-0-rails-4"
].join)
expect(onebox.translate_url).to eq api_url
end
it 'returns the correct api url for a share url' do
onebox = described_class.new("http://#{site}.com/q/#{question}")
expect(onebox.translate_url).to eq api_url
end
end
context 'when the question is from Super User' do
let(:site) { 'superuser' }
it 'returns the correct api url' do
onebox = described_class.new("http://#{site}.com/q/#{question}")
expect(onebox.translate_url).to eq api_url
end
end
context 'when the question is from Meta Stack Overflow' do
let(:site) { 'meta.stackoverflow' }
it 'returns the correct api url' do
onebox = described_class.new("http://meta.stackoverflow.com/q/#{question}")
expect(onebox.translate_url).to eq api_url
end
end
context 'when the question is from a Meta Stack Exchange subdomain' do
let(:site) { 'meta.gamedev' }
it 'returns the correct api url' do
onebox = described_class.new("http://meta.gamedev.stackexchange.com/q/#{question}")
expect(onebox.translate_url).to eq api_url
end
end
context 'when the question is from a Stack Exchange subdomain' do
let(:site) { 'gamedev' }
it 'returns the correct api url' do
onebox = described_class.new([
"http://#{site}.stackexchange.com/",
"questions/#{question}/how-to-prevent-the-too-awesome-to-use-syndrome"
].join)
expect(onebox.translate_url).to eq api_url
end
end
end
end

View File

@ -1,56 +0,0 @@
require 'spec_helper'
describe Oneboxer::TwitterOnebox do
subject { described_class.new(nil, nil) }
let(:data) { %({ "text":"#{text}", "created_at":"#{created_at}" }) }
let(:text) { '' }
let(:created_at) { '2013-06-13T22:37:05Z' }
describe '#parse' do
it 'formats the timestamp' do
expect(subject.parse(data)['created_at']).to eq '10:37PM - 13 Jun 13'
end
context 'when text contains a url' do
let(:text) { 'Twitter http://twitter.com' }
it 'wraps eack url in a link' do
expect(subject.parse(data)['text']).to eq([
"Twitter ",
'<a href="http://twitter.com" target="_blank">',
"http://twitter.com",
"</a>"
].join)
end
end
context 'when the text contains a twitter handle' do
let(:text) { 'I like @chrishunt' }
it 'wraps each handle in a link' do
expect(subject.parse(data)['text']).to eq([
"I like ",
"<a href='https://twitter.com/chrishunt' target='_blank'>",
"@chrishunt",
"</a>"
].join)
end
end
context 'when the text contains a hashtag' do
let(:text) { 'No secrets. #NSA' }
it 'wraps each hashtag in a link' do
expect(subject.parse(data)['text']).to eq([
"No secrets. ",
"<a href='https://twitter.com/search?q=%23NSA' target='_blank'>",
"#NSA",
"</a>"
].join)
end
end
end
end

View File

@ -1,18 +0,0 @@
require 'spec_helper'
require 'oneboxer'
require 'oneboxer/whitelist'
describe Oneboxer::Whitelist do
it "matches an arbitrary Discourse post link" do
Oneboxer::Whitelist.entry_for_url('http://meta.discourse.org/t/scrolling-up-not-loading-in-firefox/3340/6?123').should_not be_nil
end
it "matches an arbitrary Discourse topic link" do
Oneboxer::Whitelist.entry_for_url('http://meta.discourse.org/t/scrolling-up-not-loading-in-firefox/3340?123').should_not be_nil
end
it "Does not match on slight variation" do
Oneboxer::Whitelist.entry_for_url('http://meta.discourse.org/t/scrolling-up-not-loading-in-firefox/3340a?123').should be_nil
end
end

View File

@ -1,57 +0,0 @@
# encoding: utf-8
require 'spec_helper'
require 'oneboxer'
require 'oneboxer/wikipedia_onebox'
describe Oneboxer::WikipediaOnebox do
it "generates the expected onebox for Wikipedia" do
o = Oneboxer::WikipediaOnebox.new('http://en.wikipedia.org/wiki/Ruby')
FakeWeb.register_uri(:get, o.translate_url, response: fixture_file('oneboxer/wikipedia.response'))
FakeWeb.register_uri(:get, 'http://en.m.wikipedia.org/wiki/Ruby', response: fixture_file('oneboxer/wikipedia_redirected.response'))
o.onebox.should match_html expected_wikipedia_result
end
it "accepts .com extention" do
o = Oneboxer::WikipediaOnebox.new('http://en.wikipedia.com/wiki/Postgres')
o.translate_url.should == 'http://en.m.wikipedia.org/w/index.php?title=Postgres'
end
it "encodes identifier" do
o = Oneboxer::WikipediaOnebox.new('http://en.wikipedia.com/wiki/Café')
o.translate_url.should == 'http://en.m.wikipedia.org/w/index.php?title=Caf%C3%A9'
end
it "defaults to en locale" do
o = Oneboxer::WikipediaOnebox.new('http://wikipedia.org/wiki/Ruby_on_rails')
o.translate_url.should == 'http://en.m.wikipedia.org/w/index.php?title=Ruby_on_rails'
end
it "generates localized url" do
o = Oneboxer::WikipediaOnebox.new('http://fr.wikipedia.org/wiki/Ruby')
o.translate_url.should == 'http://fr.m.wikipedia.org/w/index.php?title=Ruby'
end
private
def expected_wikipedia_result
<<EXPECTED
<div class='onebox-result'>
<div class='source'>
<div class='info'>
<a href='http://en.wikipedia.org/wiki/Ruby' class="track-link" target="_blank">
<img class='favicon' src="/assets/favicons/wikipedia.png"> en.wikipedia.org
</a>
</div>
</div>
<div class='onebox-result-body'>
<img src="http://upload.wikimedia.org/wikipedia/commons/thumb/8/80/Ruby_-_Winza%2C_Tanzania.jpg/220px-Ruby_-_Winza%2C_Tanzania.jpg" class="thumbnail">
<h3><a href="http://en.wikipedia.org/wiki/Ruby" target="_blank">Ruby</a></h3>
A ruby is a pink to blood-red colored gemstone, a variety of the mineral corundum (aluminium oxide). The red color is caused mainly by the presence of the element chromium. Its name comes from ruber, Latin for red. Other varieties of gem-quality corundum are called sapphires. The ruby is considered one of the four precious stones, together with the sapphire, the emerald, and the diamond. Prices of rubies are primarily determined by color. The brightest and most valuable "red" called pigeon blood-...
</div>
<div class='clearfix'></div>
</div>
EXPECTED
end
end

View File

@ -1,206 +0,0 @@
require 'spec_helper'
require 'oneboxer'
describe "Dynamic Oneboxer" do
class DummyDynamicOnebox < Oneboxer::BaseOnebox
matcher do
/^https?:\/\/dummy2.localhost/
end
def onebox
"dummy2!"
end
end
before do
Oneboxer.add_onebox DummyDynamicOnebox
@dummy_onebox_url = "http://dummy2.localhost/dummy-object"
end
context 'find onebox for url' do
it 'returns blank with an unknown url' do
Oneboxer.onebox_for_url('http://asdfasdfasdfasdf.asdf').should be_blank
end
it 'returns something when matched' do
Oneboxer.onebox_for_url(@dummy_onebox_url).should be_present
end
it 'returns an instance of our class when matched' do
Oneboxer.onebox_for_url(@dummy_onebox_url).kind_of?(DummyDynamicOnebox).should be_true
end
end
end
describe Oneboxer do
# A class to help us test
class DummyOnebox < Oneboxer::BaseOnebox
matcher /^https?:\/\/dummy.localhost/
def onebox
"dummy!"
end
end
let(:dummy_onebox_url) { "http://dummy.localhost/dummy-object" }
before do
Oneboxer.add_onebox DummyOnebox
end
it 'should have matchers set up by default' do
Oneboxer.matchers.should be_present
end
context 'caching' do
let(:result) { "onebox result string" }
context "with invalidate_oneboxes true" do
it "invalidates the url" do
Oneboxer.expects(:invalidate).with(dummy_onebox_url)
Oneboxer.onebox(dummy_onebox_url, invalidate_oneboxes: true)
end
it "doesn't render from cache" do
Oneboxer.expects(:render_from_cache).never
Oneboxer.onebox(dummy_onebox_url, invalidate_oneboxes: true)
end
it "calls fetch and cache" do
Oneboxer.expects(:fetch_and_cache).returns(result)
Oneboxer.onebox(dummy_onebox_url, invalidate_oneboxes: true).should == result
end
end
context 'with invalidate_oneboxes false' do
it "doesn't invalidate the url" do
Oneboxer.expects(:invalidate).with(dummy_onebox_url).never
Oneboxer.onebox(dummy_onebox_url, invalidate_oneboxes: false)
end
it "returns render_from_cache if present" do
Oneboxer.expects(:render_from_cache).with(dummy_onebox_url).returns(result)
Oneboxer.onebox(dummy_onebox_url, invalidate_oneboxes: false).should == result
end
it "doesn't call fetch_and_cache" do
Oneboxer.expects(:render_from_cache).with(dummy_onebox_url).returns(result)
Oneboxer.expects(:fetch_and_cache).never
Oneboxer.onebox(dummy_onebox_url, invalidate_oneboxes: false)
end
it "calls fetch_and_cache if render from cache is blank" do
Oneboxer.stubs(:render_from_cache)
Oneboxer.expects(:fetch_and_cache).returns(result)
Oneboxer.onebox(dummy_onebox_url, invalidate_oneboxes: false).should == result
end
end
end
context 'find onebox for url' do
it 'returns blank with an unknown url' do
Oneboxer.onebox_for_url('http://asdfasdfasdfasdf.asdf').should be_blank
end
it 'returns something when matched' do
Oneboxer.onebox_for_url(dummy_onebox_url).should be_present
end
it 'returns an instance of our class when matched' do
Oneboxer.onebox_for_url(dummy_onebox_url).kind_of?(DummyOnebox).should be_true
end
end
describe '#nice_host' do
it 'strips www from the domain' do
DummyOnebox.new('http://www.cnn.com/thing').nice_host.should eq 'cnn.com'
end
it 'respects double TLDs' do
DummyOnebox.new('http://news.bbc.co.uk/thing').nice_host.should eq 'news.bbc.co.uk'
end
it 'returns an empty string if the URL is bogus' do
DummyOnebox.new('whatever').nice_host.should eq ''
end
it 'returns an empty string if the URL unparsable' do
DummyOnebox.new(nil).nice_host.should eq ''
end
end
context 'without caching' do
it 'calls the onebox method of our matched class' do
Oneboxer.onebox_nocache(dummy_onebox_url).should == 'dummy!'
end
end
context 'each_onebox_link' do
before do
@html = "<a href='http://discourse.org' class='onebox'>Discourse Link</a>"
end
it 'yields each url and element when given a string' do
result = Oneboxer.each_onebox_link(@html) do |url, element|
element.is_a?(Nokogiri::XML::Element).should be_true
url.should == 'http://discourse.org'
end
result.kind_of?(Nokogiri::HTML::DocumentFragment).should be_true
end
it 'yields each url and element when given a doc' do
doc = Nokogiri::HTML(@html)
Oneboxer.each_onebox_link(doc) do |url, element|
element.is_a?(Nokogiri::XML::Element).should be_true
url.should == 'http://discourse.org'
end
end
end
context "apply_onebox" do
it "is able to nuke wrapping p" do
doc = Oneboxer.apply "<p><a href='http://bla.com' class='onebox'>bla</p>" do |url, element|
"<div>foo</div>" if url == "http://bla.com"
end
doc.changed? == true
doc.to_html.should match_html "<div>foo</div>"
end
it "is able to do nothing if nil is returned" do
orig = "<p><a href='http://bla.com' class='onebox'>bla</p>"
doc = Oneboxer.apply orig do |url, element|
nil
end
doc.changed? == false
doc.to_html.should match_html orig
end
it "does not strip if there is a br in same node" do
doc = Oneboxer.apply "<p><br><a href='http://bla.com' class='onebox'>bla</p>" do |url, element|
"<div>foo</div>" if url == "http://bla.com"
end
doc.changed? == true
doc.to_html.should match_html "<p><br><div>foo</div></p>"
end
end
end

View File

@ -191,7 +191,9 @@ describe PostRevisor do
before do
SiteSetting.stubs(:newuser_max_images).returns(0)
subject.revise!(changed_by, "So, post them here!\nhttp://i.imgur.com/FGg7Vzu.gif")
url = "http://i.imgur.com/wfn7rgU.jpg"
Oneboxer.stubs(:onebox).with(url, anything).returns("<img src='#{url}'>")
subject.revise!(changed_by, "So, post them here!\n#{url}")
end
it "allows an admin to insert images into a new user's post" do
@ -209,11 +211,11 @@ describe PostRevisor do
SiteSetting.stubs(:newuser_max_images).returns(0)
url = "http://i.imgur.com/FGg7Vzu.gif"
# this test is problamatic, it leaves state in the onebox cache
Oneboxer.invalidate(url)
Oneboxer.stubs(:onebox).with(url, anything).returns("<img src='#{url}'>")
subject.revise!(post.user, "So, post them here!\n#{url}")
end
it "allows an admin to insert images into a new user's post" do
it "doesn't allow images to be inserted" do
post.errors.should be_present
end