video_info 2.4.2 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +1 -3
- data/README.md +33 -2
- data/lib/video_info.rb +44 -2
- data/lib/video_info/provider.rb +21 -4
- data/lib/video_info/providers/vimeo.rb +81 -9
- data/lib/video_info/providers/vimeoplaylist.rb +14 -13
- data/lib/video_info/providers/vkontakte.rb +1 -1
- data/lib/video_info/providers/youtube.rb +20 -51
- data/lib/video_info/providers/youtube_api.rb +72 -0
- data/lib/video_info/providers/youtube_scraper.rb +99 -0
- data/lib/video_info/providers/youtubeplaylist.rb +28 -29
- data/lib/video_info/providers/youtubeplaylist_api.rb +57 -0
- data/lib/video_info/providers/youtubeplaylist_scraper.rb +47 -0
- data/lib/video_info/version.rb +1 -1
- data/spec/lib/video_info/providers/vimeo_playlist_spec.rb +19 -18
- data/spec/lib/video_info/providers/vimeo_spec.rb +45 -21
- data/spec/lib/video_info/providers/vkontakte_spec.rb +2 -2
- data/spec/lib/video_info/providers/youtube_api_spec.rb +392 -0
- data/spec/lib/video_info/providers/youtube_playlist_api_spec.rb +173 -0
- data/spec/lib/video_info/providers/youtube_playlist_spec.rb +6 -2
- data/spec/lib/video_info/providers/youtube_spec.rb +83 -6
- data/spec/lib/video_info_spec.rb +30 -0
- data/spec/spec_helper.rb +2 -0
- data/video_info.gemspec +4 -1
- metadata +55 -196
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/_available_/with_This_video_does_not_exist_or_has_been_deleted_/_available_/.yml +0 -60
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/_available_/with_valid_video/_available_/.yml +0 -59
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/with_video_x7lni3/_date/.yml +0 -62
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/with_video_x7lni3/_description/.yml +0 -62
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/with_video_x7lni3/_duration/.yml +0 -62
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/with_video_x7lni3/_keywords/.yml +0 -62
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/with_video_x7lni3/_thumbnail_large/.yml +0 -62
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/with_video_x7lni3/_thumbnail_medium/.yml +0 -62
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/with_video_x7lni3/_thumbnail_small/.yml +0 -62
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/with_video_x7lni3/_title/.yml +0 -62
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/with_video_x7lni3/_view_count/.yml +0 -62
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/_available_/with_password_required_video/_available_/.yml +0 -119
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/_available_/with_this_video_does_not_exist_video/_available_/.yml +0 -72
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/_available_/with_valid_video/_available_/.yml +0 -76
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_date/.yml +0 -83
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_description/.yml +0 -83
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_duration/.yml +0 -83
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_height/.yml +0 -83
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_keywords/.yml +0 -83
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_thumbnail_large/.yml +0 -83
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_thumbnail_medium/.yml +0 -83
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_thumbnail_small/.yml +0 -83
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_title/.yml +0 -83
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_view_count/.yml +0 -83
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_width/.yml +0 -83
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_VimeoPlaylist/_available_/with_invalid_playlist/_available_/.yml +0 -72
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_VimeoPlaylist/_available_/with_valid_playlist/_available_/.yml +0 -76
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_VimeoPlaylist/with_playlist_1921098/_description/.yml +0 -81
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_VimeoPlaylist/with_playlist_1921098/_thumbnail_large/.yml +0 -81
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_VimeoPlaylist/with_playlist_1921098/_thumbnail_medium/.yml +0 -81
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_VimeoPlaylist/with_playlist_1921098/_thumbnail_small/.yml +0 -81
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_VimeoPlaylist/with_playlist_1921098/_title/.yml +0 -81
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_VimeoPlaylist/with_playlist_1921098/_videos/.yml +0 -114
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/_available_/with_hashes/available_/.yml +0 -2255
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/_available_/with_invalid_video/available_/.yml +0 -46
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/_available_/with_private_video/available_/.yml +0 -382
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/_available_/with_redirect/available_/.yml +0 -210
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/_available_/with_redirect_to_main_page_for_auth/available_/.yml +0 -46
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/_available_/with_valid_video/available_/.yml +0 -1657
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_kirill_lyanoi_z_video2152699_168591741_2F56fd229a9dfe2dcdbe/description/.yml +0 -730
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_kirill_lyanoi_z_video2152699_168591741_2F56fd229a9dfe2dcdbe/duration/.yml +0 -731
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_kirill_lyanoi_z_video2152699_168591741_2F56fd229a9dfe2dcdbe/embed_code/.yml +0 -732
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_kirill_lyanoi_z_video2152699_168591741_2F56fd229a9dfe2dcdbe/embed_url/.yml +0 -732
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_kirill_lyanoi_z_video2152699_168591741_2F56fd229a9dfe2dcdbe/height/.yml +0 -732
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_kirill_lyanoi_z_video2152699_168591741_2F56fd229a9dfe2dcdbe/keywords/.yml +0 -732
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_kirill_lyanoi_z_video2152699_168591741_2F56fd229a9dfe2dcdbe/title/.yml +0 -731
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_kirill_lyanoi_z_video2152699_168591741_2F56fd229a9dfe2dcdbe/view_count/.yml +0 -731
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_kirill_lyanoi_z_video2152699_168591741_2F56fd229a9dfe2dcdbe/width/.yml +0 -728
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_video-54799401_165822734/title/.yml +0 -1226
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_video39576223_108370515/description/.yml +0 -997
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_video39576223_108370515/duration/.yml +0 -997
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_video39576223_108370515/embed_code/.yml +0 -997
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_video39576223_108370515/embed_url/.yml +0 -998
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_video39576223_108370515/height/.yml +0 -998
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_video39576223_108370515/keywords/.yml +0 -997
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_video39576223_108370515/title/.yml +0 -997
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_video39576223_108370515/view_count/.yml +0 -997
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_video39576223_108370515/width/.yml +0 -998
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_videos43640822_/video43640822_168790809/title/.yml +0 -597
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/_available_/with_invalid_video/_available_/.yml +0 -69
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/_available_/with_valid_video/_available_/.yml +0 -71
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_pxonqr42is/_duration/.yml +0 -78
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_pxonqr42is/_height/.yml +0 -78
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_pxonqr42is/_thumbnail_large/.yml +0 -78
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_pxonqr42is/_thumbnail_medium/.yml +0 -78
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_pxonqr42is/_thumbnail_small/.yml +0 -78
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_pxonqr42is/_title/.yml +0 -78
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_pxonqr42is/_width/.yml +0 -78
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_rs1me54mpw/_duration/.yml +0 -78
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_rs1me54mpw/_height/.yml +0 -78
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_rs1me54mpw/_thumbnail_large/.yml +0 -78
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_rs1me54mpw/_thumbnail_medium/.yml +0 -78
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_rs1me54mpw/_thumbnail_small/.yml +0 -78
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_rs1me54mpw/_title/.yml +0 -78
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_rs1me54mpw/_width/.yml +0 -78
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/_available_/with_valid_video/_available_/.yml +0 -56
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/_available_/with_video_is_unavailable_video/_available_/.yml +0 -46
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/_available_/with_video_no_longer_available_due_to_a_copyright_claim_video/_available_/.yml +0 -46
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/with_video_mZqGqE0D0n4/_date/.yml +0 -61
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/with_video_mZqGqE0D0n4/_description/.yml +0 -63
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/with_video_mZqGqE0D0n4/_duration/.yml +0 -63
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/with_video_mZqGqE0D0n4/_keywords/.yml +0 -63
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/with_video_mZqGqE0D0n4/_thumbnail_large/.yml +0 -61
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/with_video_mZqGqE0D0n4/_thumbnail_medium/.yml +0 -61
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/with_video_mZqGqE0D0n4/_thumbnail_small/.yml +0 -61
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/with_video_mZqGqE0D0n4/_title/.yml +0 -63
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/with_video_mZqGqE0D0n4/_view_count/.yml +0 -61
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_YoutubePlaylist/_available_/with_invalid_playlist/_available_/.yml +0 -46
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_YoutubePlaylist/_available_/with_valid_playlist/_available_/.yml +0 -56
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_YoutubePlaylist/with_playlist_PL0E8117603D70E10A_in_embed_path/_videos/.yml +0 -61
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_YoutubePlaylist/with_playlist_PL9hW1uS6HUftLdHI6RIsaf/_description/.yml +0 -96
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_YoutubePlaylist/with_playlist_PL9hW1uS6HUftLdHI6RIsaf/_thumbnail_large/.yml +0 -96
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_YoutubePlaylist/with_playlist_PL9hW1uS6HUftLdHI6RIsaf/_thumbnail_medium/.yml +0 -96
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_YoutubePlaylist/with_playlist_PL9hW1uS6HUftLdHI6RIsaf/_thumbnail_small/.yml +0 -96
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_YoutubePlaylist/with_playlist_PL9hW1uS6HUftLdHI6RIsaf/_title/.yml +0 -98
- data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_YoutubePlaylist/with_playlist_PL9hW1uS6HUftLdHI6RIsaf/_videos/.yml +0 -96
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 407deea14c1eab8be2324255ee49bde34affdf01
|
4
|
+
data.tar.gz: 2ef07eb9b3fe33504a9d31fe2e1bf27959f28ecf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c5ba823f42f0798b354b3caa08ad21605e6a0c1626c07336ef04d66bd822d876150982716b4b73dd07a6d26afc7a4ce3ebbdd538037cf86f786cf6b2329a4e1b
|
7
|
+
data.tar.gz: 9717f48d8ac0814af071a7eb568f1d5a420d06a2b78cfe903bf84f2f31035e10efe372216ea396cb1d0f7ae65e7f07e85946ea5dc9fd25dbb3d7bb41e2a04292
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
Simple Ruby Gem to get video info from Dailymotion, VK, Vimeo (with playlist), Wistia and YouTube (with playlist).
|
6
6
|
|
7
|
-
Tested against Ruby
|
7
|
+
Tested against Ruby 2.2.0 and the latest versions of JRuby & Rubinius.
|
8
8
|
|
9
9
|
Install
|
10
10
|
--------
|
@@ -16,6 +16,21 @@ gem install video_info
|
|
16
16
|
Usage
|
17
17
|
-----
|
18
18
|
|
19
|
+
## Note for YouTube usage!
|
20
|
+
Youtube recently updated their API to require an API key.
|
21
|
+
|
22
|
+
To get around this, a scraper was implemented. However, the scraper can only get the date the video was posted, while the API is able to get the date and the exact time the video was posted.
|
23
|
+
|
24
|
+
You may also wish to use the API to protect against potential HTML changes that could break the scraper.
|
25
|
+
|
26
|
+
To get an API key, [follow the instructions here](https://developers.google.com/youtube/registering_an_application)
|
27
|
+
|
28
|
+
To set the API key, do the following:
|
29
|
+
``` ruby
|
30
|
+
VideoInfo.provider_api_keys = { youtube: 'YOUR_API_KEY' }
|
31
|
+
```
|
32
|
+
|
33
|
+
|
19
34
|
``` ruby
|
20
35
|
video = VideoInfo.new('http://www.dailymotion.com/video/x7lni3')
|
21
36
|
# video.available? => true
|
@@ -131,13 +146,29 @@ VideoInfo.new('http://www.youtube.com/watch?v=mZqGqE0D0n4').embed_code(iframe_at
|
|
131
146
|
=> '<iframe src="//www.youtube.com/embed/mZqGqE0D0n4?autoplay=1" frameborder="0" allowfullscreen="allowfullscreen"></iframe>'
|
132
147
|
```
|
133
148
|
|
149
|
+
If you would like to disable certain providers, you can do so by modifying the class variable `disable_providers`:
|
150
|
+
|
151
|
+
``` ruby
|
152
|
+
VideoInfo.disable_providers = %w[YouTube] # disable YouTube
|
153
|
+
VideoInfo.disable_providers = %w[Vimeo YouTube] # disable Vimeo and Youtube
|
154
|
+
VideoInfo.disable_providers = [] # enable all providers
|
155
|
+
```
|
156
|
+
|
157
|
+
Note: `disable_providers` is case-insensitive. Attempting to use a disabled provider will raise a UrlError, just like attempting to use a
|
158
|
+
non-video URL.
|
159
|
+
|
134
160
|
Author
|
135
161
|
------
|
136
162
|
|
137
163
|
[Thibaud Guillaume-Gentil](https://github.com/thibaudgg) ([@thibaudgg](https://twitter.com/thibaudgg))
|
138
164
|
|
165
|
+
Maintainers
|
166
|
+
-----------
|
167
|
+
|
168
|
+
[Thibaud Guillaume-Gentil](https://github.com/thibaudgg) ([@thibaudgg](https://twitter.com/thibaudgg))
|
169
|
+
[Vincent Heuken](https://github.com/vheuken) ([@vheuken](https://github.com/vheuken))
|
170
|
+
|
139
171
|
Contributors
|
140
172
|
------------
|
141
173
|
|
142
174
|
[https://github.com/thibaudgg/video_info/graphs/contributors](https://github.com/thibaudgg/video_info/graphs/contributors)
|
143
|
-
|
data/lib/video_info.rb
CHANGED
@@ -17,11 +17,14 @@ class VideoInfo
|
|
17
17
|
def_delegators :@provider, :provider, :video_id, :video_owner, :url, :data
|
18
18
|
def_delegators :@provider, :title, :description, :keywords, :view_count
|
19
19
|
def_delegators :@provider, :date, :duration, :width, :height
|
20
|
+
def_delegators :@provider, :thumbnail
|
20
21
|
def_delegators :@provider, :thumbnail_small, :thumbnail_medium, :thumbnail_large
|
21
22
|
def_delegators :@provider, :embed_code, :embed_url
|
22
23
|
def_delegators :@provider, :available?
|
23
24
|
def_delegators :@provider, :playlist_id, :videos
|
24
|
-
|
25
|
+
def_delegators :@provider, :author, :author_thumbnail
|
26
|
+
def_delegators :@provider, :data=
|
27
|
+
|
25
28
|
def initialize(url, options = {})
|
26
29
|
@provider = _select_provider(url, options)
|
27
30
|
end
|
@@ -41,11 +44,44 @@ class VideoInfo
|
|
41
44
|
url == other.url && video_id == other.video_id
|
42
45
|
end
|
43
46
|
|
47
|
+
@@provider_api_keys = {}
|
48
|
+
|
49
|
+
def self.provider_api_keys
|
50
|
+
@@provider_api_keys
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.provider_api_keys=(api_keys)
|
54
|
+
api_keys.keys.each do |key|
|
55
|
+
raise ArgumentError, 'Key must be a symbol!' unless key.is_a?(Symbol)
|
56
|
+
end
|
57
|
+
@@provider_api_keys = api_keys
|
58
|
+
end
|
59
|
+
|
60
|
+
@@disable_providers = []
|
61
|
+
|
62
|
+
def self.disable_providers
|
63
|
+
@@disable_providers
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.disable_providers=(providers)
|
67
|
+
@@disable_providers = providers
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.disabled_provider?(provider)
|
71
|
+
disable_providers.map(&:downcase).include?(provider.downcase)
|
72
|
+
end
|
73
|
+
|
44
74
|
private
|
45
75
|
|
46
76
|
def _select_provider(url, options)
|
47
77
|
if provider_const = _providers_const.detect { |p| p.usable?(url) }
|
48
|
-
provider_const.new(url, options)
|
78
|
+
const_provider = provider_const.new(url, options)
|
79
|
+
|
80
|
+
if defined?(const_provider.provider) && const_provider.provider
|
81
|
+
ensure_enabled_provider(const_provider.provider)
|
82
|
+
end
|
83
|
+
|
84
|
+
const_provider
|
49
85
|
else
|
50
86
|
raise UrlError, "Url is not usable by any Providers: #{url}"
|
51
87
|
end
|
@@ -54,4 +90,10 @@ class VideoInfo
|
|
54
90
|
def _providers_const
|
55
91
|
PROVIDERS.map { |p| Providers.const_get(p) }
|
56
92
|
end
|
93
|
+
|
94
|
+
def ensure_enabled_provider(provider)
|
95
|
+
if self.class.disabled_provider?(provider)
|
96
|
+
raise UrlError, "#{provider} is disabled"
|
97
|
+
end
|
98
|
+
end
|
57
99
|
end
|
data/lib/video_info/provider.rb
CHANGED
@@ -39,8 +39,25 @@ class VideoInfo
|
|
39
39
|
private
|
40
40
|
|
41
41
|
def _response_code
|
42
|
-
|
43
|
-
Net::HTTP.
|
42
|
+
uri = URI.parse(_api_url)
|
43
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
44
|
+
|
45
|
+
if (uri.scheme == 'https')
|
46
|
+
_https_response_code(http)
|
47
|
+
else
|
48
|
+
_http_response_code(http)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def _http_response_code(http)
|
53
|
+
response = http.head(_api_path, @options)
|
54
|
+
response.code
|
55
|
+
end
|
56
|
+
|
57
|
+
def _https_response_code(http)
|
58
|
+
http.use_ssl = true
|
59
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
60
|
+
response = http.head(_api_path, @options)
|
44
61
|
response.code
|
45
62
|
end
|
46
63
|
|
@@ -56,8 +73,8 @@ class VideoInfo
|
|
56
73
|
options
|
57
74
|
end
|
58
75
|
|
59
|
-
def _set_data_from_api
|
60
|
-
uri = open(
|
76
|
+
def _set_data_from_api(api_url = _api_url)
|
77
|
+
uri = open(api_url, options)
|
61
78
|
MultiJson.load(uri.read)
|
62
79
|
end
|
63
80
|
|
@@ -9,7 +9,11 @@ class VideoInfo
|
|
9
9
|
'Vimeo'
|
10
10
|
end
|
11
11
|
|
12
|
-
|
12
|
+
def api_key
|
13
|
+
VideoInfo.provider_api_keys[:vimeo]
|
14
|
+
end
|
15
|
+
|
16
|
+
%w[description].each do |method|
|
13
17
|
define_method(method) { _video[method] }
|
14
18
|
end
|
15
19
|
|
@@ -17,8 +21,50 @@ class VideoInfo
|
|
17
21
|
define_method(method) { _video[method].to_i }
|
18
22
|
end
|
19
23
|
|
24
|
+
def title
|
25
|
+
_video['name']
|
26
|
+
end
|
27
|
+
|
28
|
+
def author
|
29
|
+
_video['user']['name']
|
30
|
+
end
|
31
|
+
|
32
|
+
def author_thumbnail_id
|
33
|
+
author_uri = _video['user']['pictures']['uri']
|
34
|
+
@author_thumbnail_id ||= _parse_picture_id(author_uri)
|
35
|
+
end
|
36
|
+
|
37
|
+
def author_thumbnail(width = 75)
|
38
|
+
"https://i.vimeocdn.com/portrait/#{author_thumbnail_id}_#{width}x#{width}.jpg"
|
39
|
+
end
|
40
|
+
|
41
|
+
def thumbnail_id
|
42
|
+
@thumbnail_id ||= _parse_picture_id(_video['pictures']['uri'])
|
43
|
+
end
|
44
|
+
|
45
|
+
def thumbnail(width = 200, height = nil)
|
46
|
+
base_uri = "https://i.vimeocdn.com/video/#{thumbnail_id}"
|
47
|
+
height ? base_uri + "_#{width}x#{height}.jpg" : base_uri + "_#{width}.jpg"
|
48
|
+
end
|
49
|
+
|
50
|
+
def thumbnail_small
|
51
|
+
thumbnail(100, 75)
|
52
|
+
end
|
53
|
+
|
54
|
+
def thumbnail_medium
|
55
|
+
thumbnail(200, 150)
|
56
|
+
end
|
57
|
+
|
58
|
+
def thumbnail_large
|
59
|
+
thumbnail(640)
|
60
|
+
end
|
61
|
+
|
20
62
|
def keywords
|
21
|
-
|
63
|
+
keywords_array.join(', ')
|
64
|
+
end
|
65
|
+
|
66
|
+
def keywords_array
|
67
|
+
_video['tags'].map { |t| t['tag'] }
|
22
68
|
end
|
23
69
|
|
24
70
|
def embed_url
|
@@ -26,33 +72,55 @@ class VideoInfo
|
|
26
72
|
end
|
27
73
|
|
28
74
|
def date
|
29
|
-
Time.parse(_video['
|
75
|
+
Time.parse(_video['created_time'], Time.now.utc).utc
|
30
76
|
end
|
31
77
|
|
32
78
|
def view_count
|
33
|
-
_video['
|
79
|
+
_video['stats']['plays'].to_i
|
34
80
|
end
|
35
81
|
|
36
82
|
private
|
37
83
|
|
84
|
+
def _clean_options(options)
|
85
|
+
headers = [super, _authorization_headers, _api_version_headers]
|
86
|
+
headers.inject(&:merge)
|
87
|
+
end
|
88
|
+
|
89
|
+
def _api_version
|
90
|
+
'3.2'
|
91
|
+
end
|
92
|
+
|
93
|
+
def _authorization_headers
|
94
|
+
{ 'Authorization' => "bearer #{api_key}" }
|
95
|
+
end
|
96
|
+
|
97
|
+
def _api_version_headers
|
98
|
+
{ 'Accept' => "application/vnd.vimeo.*+json;version=#{_api_version}" }
|
99
|
+
end
|
100
|
+
|
38
101
|
def _video
|
39
|
-
data
|
102
|
+
data
|
40
103
|
end
|
41
104
|
|
42
105
|
def _url_regex
|
43
|
-
/.*\.com
|
106
|
+
/.*\.com&&
|
107
|
+
|\/(?:(?:groups\/[^\/]+\/videos\/)
|
108
|
+
|(?:ondemand|channels)(?:(?:\/less\/)
|
109
|
+
|(?:user[0-9]+\/review\/)?([0-9]+).*
|
110
|
+
|(?:\/\w*\/))|(?:video\/))?([0-9]+).*$
|
111
|
+
/x
|
44
112
|
end
|
45
113
|
|
46
114
|
def _api_base
|
47
|
-
'vimeo.com'
|
115
|
+
'api.vimeo.com'
|
48
116
|
end
|
49
117
|
|
50
118
|
def _api_path
|
51
|
-
"/
|
119
|
+
"/videos/#{video_id}"
|
52
120
|
end
|
53
121
|
|
54
122
|
def _api_url
|
55
|
-
"
|
123
|
+
"https://#{_api_base}#{_api_path}"
|
56
124
|
end
|
57
125
|
|
58
126
|
def _default_iframe_attributes
|
@@ -65,6 +133,10 @@ class VideoInfo
|
|
65
133
|
portrait: 0,
|
66
134
|
autoplay: 0 }
|
67
135
|
end
|
136
|
+
|
137
|
+
def _parse_picture_id(uri)
|
138
|
+
/\/pictures\/(\d+)/.match(uri)[1]
|
139
|
+
end
|
68
140
|
end
|
69
141
|
end
|
70
142
|
end
|
@@ -8,8 +8,10 @@ class VideoInfo
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def videos
|
11
|
-
|
12
|
-
|
11
|
+
@videos ||= _data_videos.map do |video_data|
|
12
|
+
video = Vimeo.new(video_data['link'])
|
13
|
+
video.data = video
|
14
|
+
video
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
@@ -17,7 +19,7 @@ class VideoInfo
|
|
17
19
|
"//player.vimeo.com/hubnut/album/#{playlist_id}"
|
18
20
|
end
|
19
21
|
|
20
|
-
%w[width height
|
22
|
+
%w[width height keywords view_count].each do |method|
|
21
23
|
define_method(method) { nil }
|
22
24
|
end
|
23
25
|
|
@@ -32,15 +34,19 @@ class VideoInfo
|
|
32
34
|
end
|
33
35
|
|
34
36
|
def _api_path
|
35
|
-
"/
|
37
|
+
"/albums/#{playlist_id}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def _api_path_album_videos
|
41
|
+
"/albums/#{playlist_id}/videos"
|
36
42
|
end
|
37
43
|
|
38
44
|
def _api_videos_path
|
39
|
-
"/
|
45
|
+
"/videos/#{video_id}"
|
40
46
|
end
|
41
47
|
|
42
48
|
def _api_videos_url
|
43
|
-
"
|
49
|
+
"https://#{_api_base}#{_api_path_album_videos}"
|
44
50
|
end
|
45
51
|
|
46
52
|
def _data_videos
|
@@ -49,13 +55,8 @@ class VideoInfo
|
|
49
55
|
|
50
56
|
def _set_videos_from_api
|
51
57
|
uri = open(_api_videos_url, options)
|
52
|
-
MultiJson.load(uri.read)
|
53
|
-
|
54
|
-
|
55
|
-
def _playlist_video_ids
|
56
|
-
_data_videos.map do |entry|
|
57
|
-
entry['id']
|
58
|
-
end
|
58
|
+
json = MultiJson.load(uri.read)
|
59
|
+
json['data']
|
59
60
|
end
|
60
61
|
end
|
61
62
|
end
|
@@ -1,6 +1,20 @@
|
|
1
|
+
require 'iso8601'
|
2
|
+
require_relative 'youtube_api'
|
3
|
+
require_relative 'youtube_scraper'
|
4
|
+
|
1
5
|
class VideoInfo
|
2
6
|
module Providers
|
3
7
|
class Youtube < Provider
|
8
|
+
def initialize(url, options = {})
|
9
|
+
if VideoInfo.provider_api_keys[:youtube].nil?
|
10
|
+
extend YoutubeScraper
|
11
|
+
else
|
12
|
+
extend YoutubeAPI
|
13
|
+
end
|
14
|
+
|
15
|
+
super(url, options)
|
16
|
+
end
|
17
|
+
|
4
18
|
def self.usable?(url)
|
5
19
|
url =~ /(youtube\.com\/(?!playlist|embed\/videoseries).*)|(youtu\.be)/
|
6
20
|
end
|
@@ -9,48 +23,27 @@ class VideoInfo
|
|
9
23
|
'YouTube'
|
10
24
|
end
|
11
25
|
|
12
|
-
def title
|
13
|
-
_video_entry['title']['$t']
|
14
|
-
end
|
15
|
-
|
16
|
-
%w[description keywords].each do |method|
|
17
|
-
define_method(method) { _video_media_group["media$#{method}"]['$t'] }
|
18
|
-
end
|
19
|
-
|
20
26
|
%w[width height].each do |method|
|
21
27
|
define_method(method) { nil }
|
22
28
|
end
|
23
29
|
|
24
|
-
def duration
|
25
|
-
_video_media_group['yt$duration']['seconds'].to_i
|
26
|
-
end
|
27
|
-
|
28
30
|
def embed_url
|
29
31
|
"//www.youtube.com/embed/#{video_id}"
|
30
32
|
end
|
31
33
|
|
32
|
-
def date
|
33
|
-
Time.parse(_video_entry['published']['$t'], Time.now.utc)
|
34
|
-
end
|
35
|
-
|
36
34
|
def thumbnail_small
|
37
|
-
|
35
|
+
return "https://i.ytimg.com/vi/#{video_id}/default.jpg" unless _video_snippet['thumbnails']
|
36
|
+
_video_snippet['thumbnails']['default']['url']
|
38
37
|
end
|
39
38
|
|
40
39
|
def thumbnail_medium
|
41
|
-
|
40
|
+
return "https://i.ytimg.com/vi/#{video_id}/mqdefault.jpg" unless _video_snippet['thumbnails']
|
41
|
+
_video_snippet['thumbnails']['medium']['url']
|
42
42
|
end
|
43
43
|
|
44
44
|
def thumbnail_large
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
def view_count
|
49
|
-
if _video_entry['yt$statistics']
|
50
|
-
_video_entry['yt$statistics']['viewCount'].to_i
|
51
|
-
else
|
52
|
-
0
|
53
|
-
end
|
45
|
+
return "https://i.ytimg.com/vi/#{video_id}/hqdefault.jpg" unless _video_snippet['thumbnails']
|
46
|
+
_video_snippet['thumbnails']['high']['url']
|
54
47
|
end
|
55
48
|
|
56
49
|
private
|
@@ -59,18 +52,6 @@ class VideoInfo
|
|
59
52
|
/(?:youtube(?:-nocookie)?\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/ ]{11})/i
|
60
53
|
end
|
61
54
|
|
62
|
-
def _api_base
|
63
|
-
"gdata.youtube.com"
|
64
|
-
end
|
65
|
-
|
66
|
-
def _api_path
|
67
|
-
"/feeds/api/videos/#{video_id}?v=2&alt=json"
|
68
|
-
end
|
69
|
-
|
70
|
-
def _api_url
|
71
|
-
"http://#{_api_base}#{_api_path}"
|
72
|
-
end
|
73
|
-
|
74
55
|
def _default_iframe_attributes
|
75
56
|
{ allowfullscreen: 'allowfullscreen' }
|
76
57
|
end
|
@@ -78,18 +59,6 @@ class VideoInfo
|
|
78
59
|
def _default_url_attributes
|
79
60
|
{}
|
80
61
|
end
|
81
|
-
|
82
|
-
def _video_entry
|
83
|
-
data['entry']
|
84
|
-
end
|
85
|
-
|
86
|
-
def _video_media_group
|
87
|
-
data['entry']['media$group']
|
88
|
-
end
|
89
|
-
|
90
|
-
def _video_thumbnail(id)
|
91
|
-
_video_entry['media$group']['media$thumbnail'][id]['url']
|
92
|
-
end
|
93
62
|
end
|
94
63
|
end
|
95
64
|
end
|