ruby-oembed 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/oembed.rb ADDED
@@ -0,0 +1,14 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'net/http'
4
+
5
+ require 'oembed/errors'
6
+ require 'oembed/formatters'
7
+ require 'oembed/provider'
8
+ require 'oembed/provider_discovery'
9
+ require 'oembed/providers'
10
+ require 'oembed/response'
11
+ require 'oembed/response/photo'
12
+ require 'oembed/response/video'
13
+ require 'oembed/response/link'
14
+ require 'oembed/response/rich'
@@ -0,0 +1,143 @@
1
+ [
2
+ "http://*youtube.com/watch*",
3
+ "http://*.youtube.com/v/*",
4
+ "http://youtu.be/*",
5
+ "http://*.youtube.com/user/*#*",
6
+ "http://*.youtube.com/*#*/*",
7
+ "http://www.veoh.com/*/watch/*",
8
+ "http://*justin.tv/*",
9
+ "http://*justin.tv/*/b/*",
10
+ "http://www.ustream.tv/recorded/*",
11
+ "http://www.ustream.tv/channel/*",
12
+ "http://qik.com/video/*",
13
+ "http://qik.com/*",
14
+ "http://*revision3.com/*",
15
+ "http://*.dailymotion.com/video/*",
16
+ "http://*.dailymotion.com/*/video/*",
17
+ "http://www.collegehumor.com/video:*",
18
+ "http://*twitvid.com/*",
19
+ "http://www.break.com/*/*",
20
+ "http://vids.myspace.com/index.cfm?fuseaction=vids.individual&videoid*",
21
+ "http://www.myspace.com/index.cfm?fuseaction=*&videoid*",
22
+ "http://www.metacafe.com/watch/*",
23
+ "http://blip.tv/file/*",
24
+ "http://*.blip.tv/file/*",
25
+ "http://video.google.com/videoplay?*",
26
+ "http://*revver.com/video/*",
27
+ "http://video.yahoo.com/watch/*/*",
28
+ "http://video.yahoo.com/network/*",
29
+ "http://*viddler.com/explore/*/videos/*",
30
+ "http://liveleak.com/view?*",
31
+ "http://www.liveleak.com/view?*",
32
+ "http://animoto.com/play/*",
33
+ "http://dotsub.com/view/*",
34
+ "http://www.overstream.net/view.php?oid=*",
35
+ "http://*yfrog.*/*",
36
+ "http://tweetphoto.com/*",
37
+ "http://www.flickr.com/photos/*",
38
+ "http://*twitpic.com/*",
39
+ "http://*imgur.com/*",
40
+ "http://*.posterous.com/*",
41
+ "http://post.ly/*",
42
+ "http://twitgoo.com/*",
43
+ "http://i*.photobucket.com/albums/*",
44
+ "http://gi*.photobucket.com/groups/*",
45
+ "http://phodroid.com/*/*/*",
46
+ "http://www.mobypicture.com/user/*/view/*",
47
+ "http://moby.to/*",
48
+ "http://xkcd.com/*",
49
+ "http://www.xkcd.com/*",
50
+ "http://www.asofterworld.com/index.php?id=*",
51
+ "http://www.qwantz.com/index.php?comic=*",
52
+ "http://23hq.com/*/photo/*",
53
+ "http://www.23hq.com/*/photo/*",
54
+ "http://*dribbble.com/shots/*",
55
+ "http://drbl.in/*",
56
+ "http://*.smugmug.com/*",
57
+ "http://*.smugmug.com/*#*",
58
+ "http://emberapp.com/*/images/*",
59
+ "http://emberapp.com/*/images/*/sizes/*",
60
+ "http://emberapp.com/*/collections/*/*",
61
+ "http://emberapp.com/*/categories/*/*/*",
62
+ "http://embr.it/*",
63
+ "http://picasaweb.google.com*/*/*#*",
64
+ "http://picasaweb.google.com*/lh/photo/*",
65
+ "http://picasaweb.google.com*/*/*",
66
+ "http://www.whitehouse.gov/photos-and-video/video/*",
67
+ "http://www.whitehouse.gov/video/*",
68
+ "http://wh.gov/photos-and-video/video/*",
69
+ "http://wh.gov/video/*",
70
+ "http://www.hulu.com/watch*",
71
+ "http://www.hulu.com/w/*",
72
+ "http://hulu.com/watch*",
73
+ "http://hulu.com/w/*",
74
+ "http://movieclips.com/watch/*/*/",
75
+ "http://movieclips.com/watch/*/*/*/*",
76
+ "http://*crackle.com/c/*",
77
+ "http://www.fancast.com/*/videos",
78
+ "http://www.funnyordie.com/videos/*",
79
+ "http://www.vimeo.com/groups/*/videos/*",
80
+ "http://www.vimeo.com/*",
81
+ "http://vimeo.com/groups/*/videos/*",
82
+ "http://vimeo.com/*",
83
+ "http://www.ted.com/talks/*.html*",
84
+ "http://www.ted.com/talks/lang/*/*.html*",
85
+ "http://www.ted.com/index.php/talks/*.html*",
86
+ "http://www.ted.com/index.php/talks/lang/*/*.html*",
87
+ "http://*omnisio.com/*",
88
+ "http://*nfb.ca/film/*",
89
+ "http://www.thedailyshow.com/watch/*",
90
+ "http://www.thedailyshow.com/full-episodes/*",
91
+ "http://www.thedailyshow.com/collection/*/*/*",
92
+ "http://movies.yahoo.com/movie/*/video/*",
93
+ "http://movies.yahoo.com/movie/*/info",
94
+ "http://movies.yahoo.com/movie/*/trailer",
95
+ "http://www.colbertnation.com/the-colbert-report-collections/*",
96
+ "http://www.colbertnation.com/full-episodes/*",
97
+ "http://www.colbertnation.com/the-colbert-report-videos/*",
98
+ "http://www.comedycentral.com/videos/index.jhtml?*",
99
+ "http://www.theonion.com/video/*",
100
+ "http://theonion.com/video/*",
101
+ "http://wordpress.tv/*/*/*/*/",
102
+ "http://www.traileraddict.com/trailer/*",
103
+ "http://www.traileraddict.com/clip/*",
104
+ "http://www.traileraddict.com/poster/*",
105
+ "http://www.escapistmagazine.com/videos/*",
106
+ "http://www.trailerspy.com/trailer/*/*",
107
+ "http://www.trailerspy.com/trailer/*",
108
+ "http://www.trailerspy.com/view_video.php*",
109
+ "http://soundcloud.com/*",
110
+ "http://soundcloud.com/*/*",
111
+ "http://soundcloud.com/*/sets/*",
112
+ "http://soundcloud.com/groups/*",
113
+ "http://www.lala.com/#album/*",
114
+ "http://www.lala.com/album/*",
115
+ "http://www.lala.com/#song/*",
116
+ "http://www.lala.com/song/*",
117
+ "http://www.mixcloud.com/*/*/",
118
+ "http://*amazon.*/gp/product/*",
119
+ "http://*amazon.*/*/dp/*",
120
+ "http://*amazon.*/dp/*",
121
+ "http://*amazon.*/o/ASIN/*",
122
+ "http://*amazon.*/gp/offer-listing/*",
123
+ "http://*amazon.*/*/ASIN/*",
124
+ "http://*amazon.*/gp/product/images/*",
125
+ "http://www.amzn.com/*",
126
+ "http://amzn.com/*",
127
+ "http://twitter.com/*/status/*",
128
+ "http://twitter.com/*/statuses/*",
129
+ "http://www.slideshare.net/*/*",
130
+ "http://*.scribd.com/doc/*",
131
+ "http://screenr.com/*",
132
+ "http://www.5min.com/Video/*",
133
+ "http://www.howcast.com/videos/*",
134
+ "http://www.screencast.com/*/media/*",
135
+ "http://screencast.com/*/media/*",
136
+ "http://www.screencast.com/t/*",
137
+ "http://screencast.com/t/*",
138
+ "http://www.clearspring.com/widgets/*",
139
+ "http://my.opera.com/*/albums/show.dml?id=*",
140
+ "http://my.opera.com/*/albums/showpic.dml?album=*&picture=*",
141
+ "http://tumblr.com/*",
142
+ "http://*.tumblr.com/post/*"
143
+ ]
@@ -0,0 +1,28 @@
1
+ module OEmbed
2
+ class Error < StandardError
3
+ end
4
+
5
+ class NotFound < OEmbed::Error
6
+ def to_s
7
+ "No embeddable content at '#{super}'"
8
+ end
9
+ end
10
+
11
+ class UnknownFormat < OEmbed::Error
12
+ def to_s
13
+ "The provider doesn't support the '#{super}' format"
14
+ end
15
+ end
16
+
17
+ class FormatNotSupported < OEmbed::Error
18
+ def to_s
19
+ "This server doesn't have the correct libraries installed to support the '#{super}' format"
20
+ end
21
+ end
22
+
23
+ class UnknownResponse < OEmbed::Error
24
+ def to_s
25
+ "Got unknown response (#{super}) from server"
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ module OEmbed
2
+ class Formatters
3
+ FORMATS = Hash.new { |_, format| raise OEmbed::FormatNotSupported, format }
4
+
5
+ # Load XML
6
+ begin
7
+ require 'xmlsimple'
8
+ FORMATS[:xml] = proc { |r| XmlSimple.xml_in(r, 'ForceArray' => false)}
9
+ rescue LoadError
10
+ end
11
+
12
+ # Load JSON
13
+ begin
14
+ require 'json'
15
+ FORMATS[:json] = proc { |r| ::JSON.load(r) }
16
+ rescue LoadError
17
+ end
18
+
19
+ DEFAULT = FORMATS.keys.first
20
+
21
+ def self.verify?(type)
22
+ FORMATS[type] && type
23
+ end
24
+
25
+ def self.convert(type, value)
26
+ FORMATS[type].call(value)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,86 @@
1
+ module OEmbed
2
+ class Provider
3
+ attr_accessor :format, :name, :url, :urls, :endpoint
4
+
5
+ def initialize(endpoint, format = OEmbed::Formatters::DEFAULT)
6
+ @endpoint = endpoint
7
+ @urls = []
8
+ # Try to use the best available format
9
+ @format = OEmbed::Formatters.verify?(format)
10
+ end
11
+
12
+ def <<(url)
13
+ if url.is_a? Regexp
14
+ @urls << url
15
+ return
16
+ end
17
+ full, scheme, domain, path = *url.match(%r{([^:]*)://?([^/?]*)(.*)})
18
+ domain = Regexp.escape(domain).gsub("\\*", "(.*?)").gsub("(.*?)\\.", "([^\\.]+\\.)?")
19
+ path = Regexp.escape(path).gsub("\\*", "(.*?)")
20
+ @urls << Regexp.new("^#{Regexp.escape(scheme)}://#{domain}#{path}")
21
+ end
22
+
23
+ def build(url, options = {})
24
+ raise OEmbed::NotFound, url unless include?(url)
25
+ query = options.merge({:url => url})
26
+ endpoint = @endpoint.clone
27
+
28
+ if format_in_url?
29
+ format = endpoint["{format}"] = (query[:format] || @format).to_s
30
+ query.delete(:format)
31
+ else
32
+ format = query[:format] ||= @format
33
+ end
34
+
35
+ query_string = "?" + query.inject("") do |memo, (key, value)|
36
+ "#{key}=#{value}&#{memo}"
37
+ end.chop
38
+
39
+ URI.parse(endpoint + query_string).instance_eval do
40
+ @format = format; def format; @format; end
41
+ self
42
+ end
43
+ end
44
+
45
+ def raw(url, options = {})
46
+ uri = build(url, options)
47
+
48
+ found = false
49
+ max_redirects = 4
50
+ until found
51
+ host, port = uri.host, uri.port if uri.host && uri.port
52
+ res = Net::HTTP.start(uri.host, uri.port) {|http| http.get(uri.request_uri) }
53
+ res.header['location'] ? uri = URI.parse(res.header['location']) : found = true
54
+ if max_redirects == 0
55
+ found = true
56
+ else
57
+ max_redirects = max_redirects - 1
58
+ end
59
+ end
60
+
61
+ case res
62
+ when Net::HTTPNotImplemented
63
+ raise OEmbed::UnknownFormat, uri.format
64
+ when Net::HTTPNotFound
65
+ raise OEmbed::NotFound, url
66
+ when Net::HTTPOK
67
+ res.body
68
+ else
69
+ raise OEmbed::UnknownResponse, res.code
70
+ end
71
+ end
72
+
73
+ def get(url, options = {})
74
+ options[:format] ||= @format if @format
75
+ OEmbed::Response.create_for(raw(url, options), self, options[:format])
76
+ end
77
+
78
+ def format_in_url?
79
+ @endpoint.include?("{format}")
80
+ end
81
+
82
+ def include?(url)
83
+ @urls.empty? || !!@urls.detect{ |u| u =~ url }
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,55 @@
1
+ module OEmbed
2
+ class ProviderDiscovery
3
+ class << self
4
+ def raw(url, options = {})
5
+ provider = discover_provider(url, options)
6
+ provider.raw(url, options)
7
+ end
8
+
9
+ def get(url, options = {})
10
+ provider = discover_provider(url, options)
11
+ provider.get(url, options)
12
+ end
13
+
14
+ def discover_provider(url, options = {})
15
+ uri = URI.parse(url)
16
+
17
+ res = Net::HTTP.start(uri.host, uri.port) do |http|
18
+ http.get(uri.request_uri)
19
+ end
20
+
21
+ case res
22
+ when Net::HTTPNotFound
23
+ raise OEmbed::NotFound, url
24
+ when Net::HTTPOK
25
+ format = options[:format]
26
+
27
+ if format.nil? || format == :json
28
+ provider_endpoint ||= /<link.*href=['"]*([^\s'"]+)['"]*.*application\/json\+oembed.*>/.match(res.body)
29
+ provider_endpoint ||= /<link.*application\/json\+oembed.*href=['"]*([^\s'"]+)['"]*.*>/.match(res.body)
30
+ format ||= :json if provider_endpoint
31
+ end
32
+ if format.nil? || format == :xml
33
+ provider_endpoint ||= /<link.*href=['"]*([^\s'"]+)['"]*.*application\/xml\+oembed.*>/.match(res.body)
34
+ provider_endpoint ||= /<link.*application\/xml\+oembed.*href=['"]*([^\s'"]+)['"]*.*>/.match(res.body)
35
+ format ||= :xml if provider_endpoint
36
+ end
37
+
38
+ begin
39
+ provider_endpoint = URI.parse(provider_endpoint && provider_endpoint[1])
40
+ provider_endpoint.query = nil
41
+ provider_endpoint = provider_endpoint.to_s
42
+ rescue URI::Error
43
+ raise OEmbed::NotFound, url
44
+ end
45
+
46
+
47
+ Provider.new(provider_endpoint, format || OEmbed::Formatters::DEFAULT)
48
+ else
49
+ raise OEmbed::UnknownResponse, res.code
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,156 @@
1
+ require 'rubygems'
2
+ require 'json'
3
+
4
+ module OEmbed
5
+ class Providers
6
+ class << self
7
+ @@urls = {}
8
+ @@fallback = []
9
+
10
+ def urls
11
+ @@urls
12
+ end
13
+
14
+ def register(*providers)
15
+ providers.each do |provider|
16
+ provider.urls.each do |url|
17
+ @@urls[url] = provider
18
+ end
19
+ end
20
+ end
21
+
22
+ def unregister(*providers)
23
+ providers.each do |provider|
24
+ provider.urls.each do |url|
25
+ @@urls.delete(url)
26
+ end
27
+ end
28
+ end
29
+
30
+ def register_all
31
+ register(Youtube, Flickr, Viddler, Qik, Pownce, Revision3, Hulu, Vimeo, PollEverywhere, MyOpera, ClearspringWidgets, MovieClips, TwentyThree)
32
+ end
33
+
34
+ # Takes an array of OEmbed::Provider instances or OEmbed::ProviderDiscovery
35
+ # Use this method to register fallback providers.
36
+ # When the raw or get methods are called, if the URL doesn't match
37
+ # any of the registerd url patters the fallback providers
38
+ # will be called (in order) with the URL.
39
+ #
40
+ # A common example:
41
+ # OEmbed::Providers.register_fallback(OEmbed::ProviderDiscovery, OEmbed::Providers::OohEmbed)
42
+ def register_fallback(*providers)
43
+ @@fallback += providers
44
+ end
45
+
46
+ # Returns an array of all registerd fallback providers
47
+ def fallback
48
+ @@fallback
49
+ end
50
+
51
+ def find(url)
52
+ @@urls[@@urls.keys.detect { |u| u =~ url }] || false
53
+ end
54
+
55
+ def raw(url, options = {})
56
+ provider = find(url)
57
+ if provider
58
+ provider.raw(url, options)
59
+ else
60
+ fallback.each do |p|
61
+ return p.raw(url, options) rescue OEmbed::Error
62
+ end
63
+ raise(OEmbed::NotFound)
64
+ end
65
+ end
66
+
67
+ def get(url, options = {})
68
+ provider = find(url)
69
+ if provider
70
+ provider.get(url, options)
71
+ else
72
+ fallback.each do |p|
73
+ return p.get(url, options) rescue OEmbed::Error
74
+ end
75
+ raise(OEmbed::NotFound)
76
+ end
77
+ end
78
+ end
79
+
80
+ # Custom providers:
81
+ Youtube = OEmbed::Provider.new("http://www.youtube.com/oembed/")
82
+ Youtube << "http://*.youtube.com/*"
83
+
84
+ Flickr = OEmbed::Provider.new("http://www.flickr.com/services/oembed/")
85
+ Flickr << "http://*.flickr.com/*"
86
+
87
+ Viddler = OEmbed::Provider.new("http://lab.viddler.com/services/oembed/")
88
+ Viddler << "http://*.viddler.com/*"
89
+
90
+ Qik = OEmbed::Provider.new("http://qik.com/api/oembed.{format}")
91
+ Qik << "http://qik.com/*"
92
+ Qik << "http://qik.com/video/*"
93
+
94
+ Revision3 = OEmbed::Provider.new("http://revision3.com/api/oembed/")
95
+ Revision3 << "http://*.revision3.com/*"
96
+
97
+ Hulu = OEmbed::Provider.new("http://www.hulu.com/api/oembed.{format}")
98
+ Hulu << "http://www.hulu.com/watch/*"
99
+
100
+ Vimeo = OEmbed::Provider.new("http://www.vimeo.com/api/oembed.{format}")
101
+ Vimeo << "http://*.vimeo.com/*"
102
+ Vimeo << "http://*.vimeo.com/groups/*/videos/*"
103
+
104
+ Pownce = OEmbed::Provider.new("http://api.pownce.com/2.1/oembed.{format}")
105
+ Pownce << "http://*.pownce.com/*"
106
+
107
+ # A general end point, which then calls other APIs and returns OEmbed info
108
+ OohEmbed = OEmbed::Provider.new("http://oohembed.com/oohembed/")
109
+ #OohEmbed << %r{http://yfrog.(com|ru|com.tr|it|fr|co.il|co.uk|com.pl|pl|eu|us)/(.*?)} # image & video hosting
110
+ #OohEmbed << "http://*.xkcd.com/*" # A hilarious stick figure comic
111
+ OohEmbed << "http://*.wordpress.com/*/*/*/*" # Blogging Engine & community
112
+ OohEmbed << "http://*.wikipedia.org/wiki/*" # Online encyclopedia
113
+ #OohEmbed << "http://*.twitpic.com/*" # Picture hosting for Twitter
114
+ #OohEmbed << "http://twitter.com/*/statuses/*" # Mirco-blogging network
115
+ #OohEmbed << "http://*.slideshare.net/*" # Share presentations online
116
+ #OohEmbed << "http://*.phodroid.com/*/*/*" # Photo host
117
+ #OohEmbed << "http://*.metacafe.com/watch/*" # Video host
118
+ #OohEmbed << "http://video.google.com/videoplay?*" # Video hosting
119
+ #OohEmbed << "http://*.funnyordie.com/videos/*" # Comedy video host
120
+ #OohEmbed << "http://*.thedailyshow.com/video/*" # Syndicated show
121
+ #OohEmbed << "http://*.collegehumor.com/video:*" # Comedic & original videos
122
+ #OohEmbed << %r{http://(.*?).amazon.(com|co.uk|de|ca|jp)/(.*?)/(gp/product|o/ASIN|obidos/ASIN|dp)/(.*?)} # Online product shopping
123
+ #OohEmbed << "http://*.5min.com/Video/*" # micro-video host
124
+
125
+ # A general end point, which then calls other APIs and returns OEmbed info
126
+ Embedly = OEmbed::Provider.new("http://api.embed.ly/v1/api/oembed")
127
+ urls = JSON.parse(File.open(File.dirname(__FILE__) + "/embedly_urls.json", "r").read)
128
+ urls.each do |url|
129
+ Embedly << url
130
+ end
131
+
132
+ PollEverywhere = OEmbed::Provider.new("http://www.polleverywhere.com/services/oembed/")
133
+ PollEverywhere << "http://www.polleverywhere.com/polls/*"
134
+ PollEverywhere << "http://www.polleverywhere.com/multiple_choice_polls/*"
135
+ PollEverywhere << "http://www.polleverywhere.com/free_text_polls/*"
136
+
137
+ MyOpera = OEmbed::Provider.new("http://my.opera.com/service/oembed", :json)
138
+ MyOpera << "http://my.opera.com/*"
139
+
140
+ ClearspringWidgets = OEmbed::Provider.new("http://widgets.clearspring.com/widget/v1/oembed/")
141
+ ClearspringWidgets << "http://www.clearspring.com/widgets/*"
142
+
143
+ NFBCanada = OEmbed::Provider.new("http://www.nfb.ca/remote/services/oembed/")
144
+ NFBCanada << "http://*.nfb.ca/film/*"
145
+
146
+ Scribd = OEmbed::Provider.new("http://www.scribd.com/services/oembed")
147
+ Scribd << "http://*.scribd.com/*"
148
+
149
+ MovieClips = OEmbed::Provider.new("http://movieclips.com/services/oembed/")
150
+ MovieClips << "http://movieclips.com/watch/*/*/"
151
+
152
+ TwentyThree = OEmbed::Provider.new("http://www.23hq.com/23/oembed")
153
+ TwentyThree << "http://www.23hq.com/*"
154
+
155
+ end
156
+ end