ruby-oembed 0.7.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.
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