oh-my-embed 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +9 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +164 -0
  8. data/Rakefile +6 -0
  9. data/bin/console +17 -0
  10. data/bin/setup +8 -0
  11. data/lib/oh_my_embed.rb +52 -0
  12. data/lib/oh_my_embed/crawler.rb +77 -0
  13. data/lib/oh_my_embed/provider.rb +116 -0
  14. data/lib/oh_my_embed/providers/facebook_post.rb +20 -0
  15. data/lib/oh_my_embed/providers/facebook_video.rb +15 -0
  16. data/lib/oh_my_embed/providers/flickr.rb +15 -0
  17. data/lib/oh_my_embed/providers/instagram.rb +15 -0
  18. data/lib/oh_my_embed/providers/kickstarter.rb +15 -0
  19. data/lib/oh_my_embed/providers/slideshare.rb +19 -0
  20. data/lib/oh_my_embed/providers/soundcloud.rb +14 -0
  21. data/lib/oh_my_embed/providers/spotify.rb +17 -0
  22. data/lib/oh_my_embed/providers/twitter.rb +14 -0
  23. data/lib/oh_my_embed/providers/youtube.rb +18 -0
  24. data/lib/oh_my_embed/response.rb +110 -0
  25. data/lib/oh_my_embed/version.rb +3 -0
  26. data/oh-my-embed.gemspec +33 -0
  27. data/spec/fixtures/vcr_cassettes/facebook_posts.yml +65 -0
  28. data/spec/fixtures/vcr_cassettes/facebook_videos.yml +65 -0
  29. data/spec/fixtures/vcr_cassettes/flickr.yml +90 -0
  30. data/spec/fixtures/vcr_cassettes/instagram.yml +75 -0
  31. data/spec/fixtures/vcr_cassettes/kickstarter.yml +65 -0
  32. data/spec/fixtures/vcr_cassettes/slideshare.yml +87 -0
  33. data/spec/fixtures/vcr_cassettes/soundcloud.yml +57 -0
  34. data/spec/fixtures/vcr_cassettes/spotify.yml +44 -0
  35. data/spec/fixtures/vcr_cassettes/twitter.yml +66 -0
  36. data/spec/fixtures/vcr_cassettes/youtube.yml +57 -0
  37. data/spec/oh_my_embed/crawler_spec.rb +99 -0
  38. data/spec/oh_my_embed/provider_spec.rb +103 -0
  39. data/spec/oh_my_embed/providers/facebook_post_spec.rb +40 -0
  40. data/spec/oh_my_embed/providers/facebook_video_spec.rb +40 -0
  41. data/spec/oh_my_embed/providers/flickr_spec.rb +44 -0
  42. data/spec/oh_my_embed/providers/instagram_spec.rb +44 -0
  43. data/spec/oh_my_embed/providers/kickstarter_spec.rb +44 -0
  44. data/spec/oh_my_embed/providers/slideshare_spec.rb +44 -0
  45. data/spec/oh_my_embed/providers/soundcloud_spec.rb +44 -0
  46. data/spec/oh_my_embed/providers/spotify_spec.rb +41 -0
  47. data/spec/oh_my_embed/providers/twitter_spec.rb +40 -0
  48. data/spec/oh_my_embed/providers/youtube_spec.rb +44 -0
  49. data/spec/oh_my_embed/response_spec.rb +174 -0
  50. data/spec/oh_my_embed_spec.rb +7 -0
  51. data/spec/spec_helper.rb +17 -0
  52. metadata +234 -0
@@ -0,0 +1,57 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://www.youtube.com/oembed?format=json&url=http://www.youtube.com/watch?v=EErY75MXYXI
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept-Encoding:
11
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
12
+ Accept:
13
+ - "*/*"
14
+ User-Agent:
15
+ - Ruby
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Content-Type:
22
+ - application/json
23
+ Cache-Control:
24
+ - no-cache
25
+ X-Content-Type-Options:
26
+ - nosniff
27
+ X-Xss-Protection:
28
+ - 1; mode=block; report=https://www.google.com/appserve/security-bugs/log/youtube
29
+ Strict-Transport-Security:
30
+ - max-age=604800
31
+ P3p:
32
+ - CP="This is not a P3P policy! See http://support.google.com/accounts/answer/151657?hl=en
33
+ for more info."
34
+ Expires:
35
+ - Tue, 27 Apr 1971 19:44:06 EST
36
+ Date:
37
+ - Sun, 08 May 2016 09:52:44 GMT
38
+ Server:
39
+ - Ytfe_Worker
40
+ Alternate-Protocol:
41
+ - 443:quic
42
+ Alt-Svc:
43
+ - quic=":443"; ma=2592000; v="33,32,31,30,29,28,27,26,25"
44
+ Transfer-Encoding:
45
+ - chunked
46
+ body:
47
+ encoding: ASCII-8BIT
48
+ string: '{"author_name": "NyaAnimeParty", "author_url": "https:\/\/www.youtube.com\/user\/NyaAnimeParty",
49
+ "thumbnail_url": "https:\/\/i.ytimg.com\/vi\/EErY75MXYXI\/hqdefault.jpg",
50
+ "provider_name": "YouTube", "title": "Nyan Cat - 24 Hour Edition", "type":
51
+ "video", "version": "1.0", "height": 344, "thumbnail_height": 360, "width":
52
+ 459, "thumbnail_width": 480, "provider_url": "https:\/\/www.youtube.com\/",
53
+ "html": "\u003ciframe width=\"459\" height=\"344\" src=\"https:\/\/www.youtube.com\/embed\/EErY75MXYXI?feature=oembed\"
54
+ frameborder=\"0\" allowfullscreen\u003e\u003c\/iframe\u003e"}'
55
+ http_version:
56
+ recorded_at: Sun, 08 May 2016 09:52:44 GMT
57
+ recorded_with: VCR 3.0.1
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+
3
+ class OhMyEmbed::Providers::BuildInDummy < OhMyEmbed::Provider
4
+ self.schemes = [
5
+ '//*.example.com/*'
6
+ ]
7
+ end
8
+
9
+ describe OhMyEmbed::Crawler do
10
+ let(:crawler) { OhMyEmbed::Crawler.new }
11
+ let(:url) { 'http://www.example.com/my-content' }
12
+
13
+ describe '#initialize' do
14
+ it 'holds the providers in a set' do
15
+ expect(crawler.providers).to be_a Set
16
+ end
17
+
18
+ it 'register the default providers with option all: true' do
19
+ expect_any_instance_of(OhMyEmbed::Crawler).to receive(:register_all_build_in_providers)
20
+
21
+ OhMyEmbed::Crawler.new all: true
22
+ end
23
+
24
+ it 'calls register with all given args' do
25
+ expect_any_instance_of(OhMyEmbed::Crawler).to receive(:register).with(:a)
26
+ expect_any_instance_of(OhMyEmbed::Crawler).to receive(:register).with(:b)
27
+
28
+ OhMyEmbed::Crawler.new :a, :b
29
+ end
30
+ end
31
+
32
+ describe '#register' do
33
+ it 'finds the provider by symbol and add it to the providers list' do
34
+ expect{ crawler.register(:build_in_dummy) }.to change{ crawler.providers.count }.from(0).to(1)
35
+ expect(crawler.providers.first).to be OhMyEmbed::Providers::BuildInDummy
36
+ end
37
+
38
+ it 'it add the provider class to the providers list' do
39
+ expect{ crawler.register(OhMyEmbed::Providers::BuildInDummy) }.to change{ crawler.providers.count }.from(0).to(1)
40
+ expect(crawler.providers.first).to be OhMyEmbed::Providers::BuildInDummy
41
+ end
42
+
43
+ it 'raises an error if no provider class found' do
44
+ expect{ crawler.register :yolo }.to raise_error OhMyEmbed::UnknownProvider
45
+ end
46
+ end
47
+
48
+ describe '#register_all_build_in_providers' do
49
+ it 'adds all the build-in providers' do
50
+ expect{ crawler.register_all_build_in_providers }.to change{ crawler.providers.count }
51
+ expect(crawler.providers.include?(OhMyEmbed::Providers::BuildInDummy)).to be true
52
+ end
53
+ end
54
+
55
+ describe '#build_in_providers' do
56
+ it 'returns a symbols array with all build in providers' do
57
+ build_in_providers = crawler.build_in_providers
58
+ expect(build_in_providers).to be_a Array
59
+ expect(build_in_providers.all?{ |p| p.is_a? Symbol }).to be true
60
+ expect(build_in_providers.include?(:BuildInDummy)).to be true
61
+ end
62
+ end
63
+
64
+ context 'crawler with a dummy provider' do
65
+ before do
66
+ crawler.register :build_in_dummy
67
+ end
68
+
69
+ describe '#fetch' do
70
+ it 'calls fetch on the found provider and return an OhMyEmbed::Response' do
71
+ expect(OhMyEmbed::Providers::BuildInDummy).to receive(:fetch).with(url).and_return(OhMyEmbed::Response.new(OhMyEmbed::Providers::BuildInDummy, url))
72
+ response = crawler.fetch(url)
73
+
74
+ expect(response).to be_a OhMyEmbed::Response
75
+ end
76
+ end
77
+
78
+ describe '#provider_for' do
79
+ it 'raises a OhMyEmbed::UnknownProvider error if nothing matched' do
80
+ expect{ crawler.provider_for('https://google.de/content') }.to raise_error OhMyEmbed::ProviderNotFound
81
+ end
82
+
83
+ it 'finds and return the matching provider' do
84
+ provider = crawler.provider_for(url)
85
+ expect(provider).to be OhMyEmbed::Providers::BuildInDummy
86
+ end
87
+ end
88
+
89
+ describe '#embeddable?' do
90
+ it 'returns true for an url that matches a provider schema' do
91
+ expect(crawler.embeddable?(url)).to be true
92
+ end
93
+
94
+ it 'returns false if no provider matches' do
95
+ expect(crawler.embeddable?('https://google.de/content')).to be false
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,103 @@
1
+ require 'spec_helper'
2
+
3
+ class DummyProvider < OhMyEmbed::Provider
4
+ self.provider_name = 'My Dummy Provider'
5
+ self.endpoint = 'https://www.example.com/api/oembed'
6
+ self.schemes = [
7
+ '//*.example.com/*',
8
+ 'http://www.example.com/*/*',
9
+ ]
10
+ self.custom_mapping = {
11
+ 'type' => 'custom_type'
12
+ }
13
+ end
14
+
15
+ describe OhMyEmbed::Provider do
16
+ describe '::regex' do
17
+ it 'returns a union regex to match both url schemes' do
18
+ regex = DummyProvider.regex
19
+ expect(regex).to match 'https://www.example.com/yolo'
20
+ expect(regex).to match 'http://www.example.com/x/y'
21
+ end
22
+ end
23
+
24
+ describe '::regexify' do
25
+ it 'does nothing with an Regexp object' do
26
+ regex = Regexp.new('.*')
27
+ expect(DummyProvider.regexify(regex)).to be regex
28
+ end
29
+
30
+ it 'creates a regular expression from string' do
31
+ result = DummyProvider.regexify(DummyProvider.schemes.last)
32
+ expect(result).to be_a Regexp
33
+ expect(result).to eq /^http:\/\/www\.example\.com\/(.*?)\/(.*?)$/i
34
+ expect(result).to match 'http://www.example.com/yolo/swag'
35
+ end
36
+
37
+ it 'prepends http and https if no protocol given' do
38
+ result = DummyProvider.regexify(DummyProvider.schemes.first)
39
+ expect(result).to be_a Regexp
40
+ expect(result).to eq /^(https:|http:)\/\/(.*?)\.example\.com\/(.*?)$/i
41
+ expect(result).to match 'https://rofl.example.com/yolo'
42
+ end
43
+ end
44
+
45
+ describe '#fetch' do
46
+ it 'requests the providers endpoint with correct params' do
47
+ stub = stub_request(:get, /^https:\/\/www\.example\.com\/api\/oembed/).to_return do |request|
48
+ params = CGI::parse(request.uri.query)
49
+ expect(params['format'].first).to eq 'json'
50
+ expect(params['url'].first).to eq 'http://example.com/my/content'
51
+
52
+ { body: '{}' }
53
+ end
54
+
55
+ DummyProvider.fetch('http://example.com/my/content')
56
+
57
+ expect(stub).to have_been_requested
58
+ end
59
+
60
+ it 'fails with an OhMyEmbed::NotFound on staus 404 (not found)' do
61
+ stub_request(:get, /^https:\/\/www\.example\.com\/api\/oembed/).to_return(status: [404, 'Not Found'])
62
+ expect{ DummyProvider.fetch('http://example.com/my/content') }.to raise_error OhMyEmbed::NotFound
63
+ end
64
+
65
+ it 'fails with an OhMyEmbed::PermissionDenied on staus 401 (unauthorized)' do
66
+ stub_request(:get, /^https:\/\/www\.example\.com\/api\/oembed/).to_return(status: [401, 'Unauthorized'])
67
+ expect{ DummyProvider.fetch('http://example.com/my/content') }.to raise_error OhMyEmbed::PermissionDenied
68
+ end
69
+
70
+ it 'fails with an OhMyEmbed::FormatNotSupportet on status 501 (not implemented)' do
71
+ stub_request(:get, /^https:\/\/www\.example\.com\/api\/oembed/).to_return(status: [501, 'Not Implemented'])
72
+ expect{ DummyProvider.fetch('http://example.com/my/content') }.to raise_error OhMyEmbed::FormatNotSupported
73
+ end
74
+
75
+ it 'fails with an OhMyEmbed::Error on request timeout' do
76
+ stub_request(:get, /^https:\/\/www\.example\.com\/api\/oembed/).to_timeout
77
+ expect{ DummyProvider.fetch('http://example.com/my/content') }.to raise_error OhMyEmbed::Error
78
+ end
79
+
80
+ it 'fails with an OhMyEmbed::ParseError if endpoint returns malformed json' do
81
+ stub_request(:get, /^https:\/\/www\.example\.com\/api\/oembed/).to_return(body: '<yolo this="is xml">')
82
+
83
+ expect{ DummyProvider.fetch('http://example.com/my/content') }.to raise_error OhMyEmbed::ParseError
84
+ end
85
+ end
86
+
87
+ describe '#mapping' do
88
+ it 'returns a hash where defaults merged with the custom mapping' do
89
+ expect(DummyProvider.mapping['type']).to eq 'custom_type'
90
+ expect(DummyProvider.mapping['provider_name']).to eq 'provider_name'
91
+ end
92
+ end
93
+
94
+ describe '#provider_name' do
95
+ it 'returns the provider name if given' do
96
+ expect(DummyProvider.provider_name).to eq 'My Dummy Provider'
97
+ end
98
+
99
+ it 'return the provider_name extracted from class name if no provider_name given' do
100
+ expect(OhMyEmbed::Provider.provider_name).to eq 'Provider'
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe OhMyEmbed::Providers::FacebookPost do
4
+ let(:provider) { OhMyEmbed::Providers::FacebookPost }
5
+ let(:content_url) { 'https://www.facebook.com/FacebookDeutschland/posts/10153796066380932' }
6
+
7
+ it 'the content_url matches the schema' do
8
+ expect(provider.regex).to match content_url
9
+ end
10
+
11
+ describe 'fetching' do
12
+ it 'returns a rich response with required attributes' do
13
+ VCR.use_cassette('facebook_posts') do
14
+ response = provider.fetch(content_url)
15
+
16
+ expect(response).to be_a OhMyEmbed::Response
17
+
18
+ expect(response.type).to eq :rich
19
+
20
+ expect(response.provider_name).to eq 'Facebook'
21
+ expect(response.provider_url).to eq 'https://www.facebook.com'
22
+
23
+ expect(response.url).to eq content_url
24
+
25
+ expect(response.title).to be nil
26
+
27
+ expect(response.author).to eq({
28
+ name: 'Facebook',
29
+ url: 'https://www.facebook.com/FacebookDeutschland/',
30
+ })
31
+
32
+ expect(response.thumbnail).to be nil
33
+
34
+ expect(response.embed[:html]).to be_a String
35
+ expect(response.embed[:width]).to eq 552
36
+ expect(response.embed[:height]).to be nil
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe OhMyEmbed::Providers::FacebookVideo do
4
+ let(:provider) { OhMyEmbed::Providers::FacebookVideo }
5
+ let(:content_url) { 'https://www.facebook.com/facebook/videos/10153231379946729/' }
6
+
7
+ it 'the content_url matches the schema' do
8
+ expect(provider.regex).to match content_url
9
+ end
10
+
11
+ describe 'fetching' do
12
+ it 'returns a video response with required attributes' do
13
+ VCR.use_cassette('facebook_videos') do
14
+ response = provider.fetch(content_url)
15
+
16
+ expect(response).to be_a OhMyEmbed::Response
17
+
18
+ expect(response.type).to eq :video
19
+
20
+ expect(response.provider_name).to eq 'Facebook'
21
+ expect(response.provider_url).to eq 'https://www.facebook.com'
22
+
23
+ expect(response.url).to eq content_url
24
+
25
+ expect(response.title).to be nil
26
+
27
+ expect(response.author).to eq({
28
+ name: 'Facebook',
29
+ url: 'https://www.facebook.com/facebook/',
30
+ })
31
+
32
+ expect(response.thumbnail).to be nil
33
+
34
+ expect(response.embed[:html]).to be_a String
35
+ expect(response.embed[:width]).to eq 500
36
+ expect(response.embed[:height]).to eq 281
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe OhMyEmbed::Providers::Flickr do
4
+ let(:provider) { OhMyEmbed::Providers::Flickr }
5
+ let(:content_url) { 'https://www.flickr.com/photos/66038491@N06/26861401435/in/explore-2016-05-07/' }
6
+
7
+ it 'the content_url matches the schema' do
8
+ expect(provider.regex).to match content_url
9
+ end
10
+
11
+ describe 'fetching' do
12
+ it 'returns a photo response with required attributes' do
13
+ VCR.use_cassette('flickr') do
14
+ response = provider.fetch(content_url)
15
+
16
+ expect(response).to be_a OhMyEmbed::Response
17
+
18
+ expect(response.type).to eq :photo
19
+
20
+ expect(response.provider_name).to eq 'Flickr'
21
+ expect(response.provider_url).to eq 'https://www.flickr.com/'
22
+
23
+ expect(response.url).to eq 'https://farm8.staticflickr.com/7231/26861401435_c1dbfe8703_b.jpg'
24
+
25
+ expect(response.title).to eq 'T-21'
26
+
27
+ expect(response.author).to eq({
28
+ name: 'BeyondBrickz',
29
+ url: 'https://www.flickr.com/photos/66038491@N06/',
30
+ })
31
+
32
+ expect(response.thumbnail).to eq({
33
+ url: 'https://farm8.staticflickr.com/7231/26861401435_c1dbfe8703_q.jpg',
34
+ width: 150,
35
+ height: 150,
36
+ })
37
+
38
+ expect(response.embed[:html]).to be_a String
39
+ expect(response.embed[:width]).to eq '1024'
40
+ expect(response.embed[:height]).to eq '629'
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe OhMyEmbed::Providers::Instagram do
4
+ let(:provider) { OhMyEmbed::Providers::Instagram }
5
+ let(:content_url) { 'http://instagr.am/p/fA9uwTtkSN' }
6
+
7
+ it 'the content_url matches the schema' do
8
+ expect(provider.regex).to match content_url
9
+ end
10
+
11
+ describe 'fetching' do
12
+ it 'returns a rich response with required attributes' do
13
+ VCR.use_cassette('instagram') do
14
+ response = provider.fetch(content_url)
15
+
16
+ expect(response).to be_a OhMyEmbed::Response
17
+
18
+ expect(response.type).to eq :rich
19
+
20
+ expect(response.provider_name).to eq 'Instagram'
21
+ expect(response.provider_url).to eq 'https://www.instagram.com'
22
+
23
+ expect(response.url).to eq content_url
24
+
25
+ expect(response.title).to eq 'Wii Gato (Lipe Sleep)'
26
+
27
+ expect(response.author).to eq({
28
+ name: 'diegoquinteiro',
29
+ url: 'https://www.instagram.com/diegoquinteiro',
30
+ })
31
+
32
+ expect(response.thumbnail).to eq({
33
+ url: 'https://scontent-fra3-1.cdninstagram.com/t51.2885-15/e15/11358196_1472850273007829_614249870_n.jpg?ig_cache_key=NTU4NzE3ODQ3NTk3MzY4NDYx.2',
34
+ width: 640,
35
+ height: 640,
36
+ })
37
+
38
+ expect(response.embed[:html]).to be_a String
39
+ expect(response.embed[:width]).to eq 658
40
+ expect(response.embed[:height]).to be nil
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe OhMyEmbed::Providers::Kickstarter do
4
+ let(:provider) { OhMyEmbed::Providers::Kickstarter }
5
+ let(:content_url) { 'https://www.kickstarter.com/projects/531257408/professional-3-stage-knife-sharpener?ref=category_popular' }
6
+
7
+ it 'the content_url matches the schema' do
8
+ expect(provider.regex).to match content_url
9
+ end
10
+
11
+ describe 'fetching' do
12
+ it 'returns a rich response with required attributes' do
13
+ VCR.use_cassette('kickstarter') do
14
+ response = provider.fetch(content_url)
15
+
16
+ expect(response).to be_a OhMyEmbed::Response
17
+
18
+ expect(response.type).to eq :rich
19
+
20
+ expect(response.provider_name).to eq 'Kickstarter'
21
+ expect(response.provider_url).to eq 'https://www.kickstarter.com/'
22
+
23
+ expect(response.url).to eq content_url
24
+
25
+ expect(response.title).to eq 'Professional 3 Stage Knife Sharpener'
26
+
27
+ expect(response.author).to eq({
28
+ name: 'Kongqiang',
29
+ url: 'https://www.kickstarter.com/profile/531257408',
30
+ })
31
+
32
+ expect(response.thumbnail).to eq({
33
+ url: 'https://ksr-ugc.imgix.net/projects/2452435/photo-original.jpg?w=560&h=315&fit=fill&bg=FFFFFF&v=1461877181&auto=format&q=92&s=aae8e61c91e611fd27cc2db1c25a8916',
34
+ width: 560,
35
+ height: 315,
36
+ })
37
+
38
+ expect(response.embed[:html]).to be_a String
39
+ expect(response.embed[:width]).to eq 480
40
+ expect(response.embed[:height]).to eq 270
41
+ end
42
+ end
43
+ end
44
+ end