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.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +1 -3
  4. data/README.md +33 -2
  5. data/lib/video_info.rb +44 -2
  6. data/lib/video_info/provider.rb +21 -4
  7. data/lib/video_info/providers/vimeo.rb +81 -9
  8. data/lib/video_info/providers/vimeoplaylist.rb +14 -13
  9. data/lib/video_info/providers/vkontakte.rb +1 -1
  10. data/lib/video_info/providers/youtube.rb +20 -51
  11. data/lib/video_info/providers/youtube_api.rb +72 -0
  12. data/lib/video_info/providers/youtube_scraper.rb +99 -0
  13. data/lib/video_info/providers/youtubeplaylist.rb +28 -29
  14. data/lib/video_info/providers/youtubeplaylist_api.rb +57 -0
  15. data/lib/video_info/providers/youtubeplaylist_scraper.rb +47 -0
  16. data/lib/video_info/version.rb +1 -1
  17. data/spec/lib/video_info/providers/vimeo_playlist_spec.rb +19 -18
  18. data/spec/lib/video_info/providers/vimeo_spec.rb +45 -21
  19. data/spec/lib/video_info/providers/vkontakte_spec.rb +2 -2
  20. data/spec/lib/video_info/providers/youtube_api_spec.rb +392 -0
  21. data/spec/lib/video_info/providers/youtube_playlist_api_spec.rb +173 -0
  22. data/spec/lib/video_info/providers/youtube_playlist_spec.rb +6 -2
  23. data/spec/lib/video_info/providers/youtube_spec.rb +83 -6
  24. data/spec/lib/video_info_spec.rb +30 -0
  25. data/spec/spec_helper.rb +2 -0
  26. data/video_info.gemspec +4 -1
  27. metadata +55 -196
  28. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/_available_/with_This_video_does_not_exist_or_has_been_deleted_/_available_/.yml +0 -60
  29. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/_available_/with_valid_video/_available_/.yml +0 -59
  30. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/with_video_x7lni3/_date/.yml +0 -62
  31. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/with_video_x7lni3/_description/.yml +0 -62
  32. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/with_video_x7lni3/_duration/.yml +0 -62
  33. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/with_video_x7lni3/_keywords/.yml +0 -62
  34. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/with_video_x7lni3/_thumbnail_large/.yml +0 -62
  35. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/with_video_x7lni3/_thumbnail_medium/.yml +0 -62
  36. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/with_video_x7lni3/_thumbnail_small/.yml +0 -62
  37. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/with_video_x7lni3/_title/.yml +0 -62
  38. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Dailymotion/with_video_x7lni3/_view_count/.yml +0 -62
  39. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/_available_/with_password_required_video/_available_/.yml +0 -119
  40. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/_available_/with_this_video_does_not_exist_video/_available_/.yml +0 -72
  41. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/_available_/with_valid_video/_available_/.yml +0 -76
  42. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_date/.yml +0 -83
  43. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_description/.yml +0 -83
  44. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_duration/.yml +0 -83
  45. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_height/.yml +0 -83
  46. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_keywords/.yml +0 -83
  47. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_thumbnail_large/.yml +0 -83
  48. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_thumbnail_medium/.yml +0 -83
  49. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_thumbnail_small/.yml +0 -83
  50. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_title/.yml +0 -83
  51. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_view_count/.yml +0 -83
  52. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vimeo/with_video_898029/_width/.yml +0 -83
  53. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_VimeoPlaylist/_available_/with_invalid_playlist/_available_/.yml +0 -72
  54. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_VimeoPlaylist/_available_/with_valid_playlist/_available_/.yml +0 -76
  55. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_VimeoPlaylist/with_playlist_1921098/_description/.yml +0 -81
  56. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_VimeoPlaylist/with_playlist_1921098/_thumbnail_large/.yml +0 -81
  57. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_VimeoPlaylist/with_playlist_1921098/_thumbnail_medium/.yml +0 -81
  58. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_VimeoPlaylist/with_playlist_1921098/_thumbnail_small/.yml +0 -81
  59. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_VimeoPlaylist/with_playlist_1921098/_title/.yml +0 -81
  60. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_VimeoPlaylist/with_playlist_1921098/_videos/.yml +0 -114
  61. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/_available_/with_hashes/available_/.yml +0 -2255
  62. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/_available_/with_invalid_video/available_/.yml +0 -46
  63. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/_available_/with_private_video/available_/.yml +0 -382
  64. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/_available_/with_redirect/available_/.yml +0 -210
  65. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/_available_/with_redirect_to_main_page_for_auth/available_/.yml +0 -46
  66. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/_available_/with_valid_video/available_/.yml +0 -1657
  67. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_kirill_lyanoi_z_video2152699_168591741_2F56fd229a9dfe2dcdbe/description/.yml +0 -730
  68. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_kirill_lyanoi_z_video2152699_168591741_2F56fd229a9dfe2dcdbe/duration/.yml +0 -731
  69. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_kirill_lyanoi_z_video2152699_168591741_2F56fd229a9dfe2dcdbe/embed_code/.yml +0 -732
  70. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_kirill_lyanoi_z_video2152699_168591741_2F56fd229a9dfe2dcdbe/embed_url/.yml +0 -732
  71. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_kirill_lyanoi_z_video2152699_168591741_2F56fd229a9dfe2dcdbe/height/.yml +0 -732
  72. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_kirill_lyanoi_z_video2152699_168591741_2F56fd229a9dfe2dcdbe/keywords/.yml +0 -732
  73. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_kirill_lyanoi_z_video2152699_168591741_2F56fd229a9dfe2dcdbe/title/.yml +0 -731
  74. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_kirill_lyanoi_z_video2152699_168591741_2F56fd229a9dfe2dcdbe/view_count/.yml +0 -731
  75. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_kirill_lyanoi_z_video2152699_168591741_2F56fd229a9dfe2dcdbe/width/.yml +0 -728
  76. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_video-54799401_165822734/title/.yml +0 -1226
  77. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_video39576223_108370515/description/.yml +0 -997
  78. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_video39576223_108370515/duration/.yml +0 -997
  79. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_video39576223_108370515/embed_code/.yml +0 -997
  80. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_video39576223_108370515/embed_url/.yml +0 -998
  81. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_video39576223_108370515/height/.yml +0 -998
  82. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_video39576223_108370515/keywords/.yml +0 -997
  83. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_video39576223_108370515/title/.yml +0 -997
  84. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_video39576223_108370515/view_count/.yml +0 -997
  85. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_video39576223_108370515/width/.yml +0 -998
  86. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Vkontakte/with_video_videos43640822_/video43640822_168790809/title/.yml +0 -597
  87. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/_available_/with_invalid_video/_available_/.yml +0 -69
  88. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/_available_/with_valid_video/_available_/.yml +0 -71
  89. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_pxonqr42is/_duration/.yml +0 -78
  90. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_pxonqr42is/_height/.yml +0 -78
  91. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_pxonqr42is/_thumbnail_large/.yml +0 -78
  92. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_pxonqr42is/_thumbnail_medium/.yml +0 -78
  93. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_pxonqr42is/_thumbnail_small/.yml +0 -78
  94. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_pxonqr42is/_title/.yml +0 -78
  95. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_pxonqr42is/_width/.yml +0 -78
  96. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_rs1me54mpw/_duration/.yml +0 -78
  97. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_rs1me54mpw/_height/.yml +0 -78
  98. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_rs1me54mpw/_thumbnail_large/.yml +0 -78
  99. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_rs1me54mpw/_thumbnail_medium/.yml +0 -78
  100. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_rs1me54mpw/_thumbnail_small/.yml +0 -78
  101. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_rs1me54mpw/_title/.yml +0 -78
  102. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Wistia/with_video_rs1me54mpw/_width/.yml +0 -78
  103. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/_available_/with_valid_video/_available_/.yml +0 -56
  104. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/_available_/with_video_is_unavailable_video/_available_/.yml +0 -46
  105. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/_available_/with_video_no_longer_available_due_to_a_copyright_claim_video/_available_/.yml +0 -46
  106. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/with_video_mZqGqE0D0n4/_date/.yml +0 -61
  107. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/with_video_mZqGqE0D0n4/_description/.yml +0 -63
  108. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/with_video_mZqGqE0D0n4/_duration/.yml +0 -63
  109. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/with_video_mZqGqE0D0n4/_keywords/.yml +0 -63
  110. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/with_video_mZqGqE0D0n4/_thumbnail_large/.yml +0 -61
  111. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/with_video_mZqGqE0D0n4/_thumbnail_medium/.yml +0 -61
  112. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/with_video_mZqGqE0D0n4/_thumbnail_small/.yml +0 -61
  113. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/with_video_mZqGqE0D0n4/_title/.yml +0 -63
  114. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_Youtube/with_video_mZqGqE0D0n4/_view_count/.yml +0 -61
  115. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_YoutubePlaylist/_available_/with_invalid_playlist/_available_/.yml +0 -46
  116. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_YoutubePlaylist/_available_/with_valid_playlist/_available_/.yml +0 -56
  117. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_YoutubePlaylist/with_playlist_PL0E8117603D70E10A_in_embed_path/_videos/.yml +0 -61
  118. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_YoutubePlaylist/with_playlist_PL9hW1uS6HUftLdHI6RIsaf/_description/.yml +0 -96
  119. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_YoutubePlaylist/with_playlist_PL9hW1uS6HUftLdHI6RIsaf/_thumbnail_large/.yml +0 -96
  120. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_YoutubePlaylist/with_playlist_PL9hW1uS6HUftLdHI6RIsaf/_thumbnail_medium/.yml +0 -96
  121. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_YoutubePlaylist/with_playlist_PL9hW1uS6HUftLdHI6RIsaf/_thumbnail_small/.yml +0 -96
  122. data/spec/fixtures/vcr_cassettes/VideoInfo_Providers_YoutubePlaylist/with_playlist_PL9hW1uS6HUftLdHI6RIsaf/_title/.yml +0 -98
  123. 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: 456811952d85d6b9e52f876b2a599eb40f8b1cb7
4
- data.tar.gz: f87c2d89023c932c91d99f32d0f8dd36ce236bf5
3
+ metadata.gz: 407deea14c1eab8be2324255ee49bde34affdf01
4
+ data.tar.gz: 2ef07eb9b3fe33504a9d31fe2e1bf27959f28ecf
5
5
  SHA512:
6
- metadata.gz: 85fdd40ea59d64ea9e9705f796e40137d9fcec6083131de58f1b6bd690e1f1b278fc9f569c87e39e43e4b6306bca5989aaf79595f95770e7661baf22addb2aea
7
- data.tar.gz: be70db584d9f01c9d14e26cc7b5cfe0feb28d2827b6545b7f36ca3c2ee5a1eb51683dd7979d9cc69210a6db69791aaae0ba99957ce92341bb0e363490fb65b3c
6
+ metadata.gz: c5ba823f42f0798b354b3caa08ad21605e6a0c1626c07336ef04d66bd822d876150982716b4b73dd07a6d26afc7a4ce3ebbdd538037cf86f786cf6b2329a4e1b
7
+ data.tar.gz: 9717f48d8ac0814af071a7eb568f1d5a420d06a2b78cfe903bf84f2f31035e10efe372216ea396cb1d0f7ae65e7f07e85946ea5dc9fd25dbb3d7bb41e2a04292
data/.gitignore CHANGED
@@ -18,6 +18,7 @@ coverage
18
18
  rdoc
19
19
  pkg
20
20
  Gemfile.lock
21
+ spec/fixtures/
21
22
 
22
23
  ## PROJECT::SPECIFIC
23
24
  .bundle/config
@@ -1,12 +1,10 @@
1
1
  language: ruby
2
2
  bundler_args: --without tool
3
3
  rvm:
4
- - 1.9.3
5
- - 2.0.0
6
- - 2.1.0
7
4
  - 2.2.0
8
5
  - jruby
9
6
  - rbx
10
7
  matrix:
11
8
  allow_failures:
12
9
  - rvm: rbx
10
+ - rvm: jruby
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 1.9.3, 2.0.0, 2.1.0 and the latest versions of JRuby & Rubinius.
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
-
@@ -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
@@ -39,8 +39,25 @@ class VideoInfo
39
39
  private
40
40
 
41
41
  def _response_code
42
- response = nil
43
- Net::HTTP.start(_api_base, 80) { |http| response = http.head(_api_path) }
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(_api_url, options)
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
- %w[title description thumbnail_small thumbnail_medium thumbnail_large].each do |method|
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
- _video['tags']
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['upload_date'], Time.now.utc).utc
75
+ Time.parse(_video['created_time'], Time.now.utc).utc
30
76
  end
31
77
 
32
78
  def view_count
33
- _video['stats_number_of_plays'].to_i
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 && data.first
102
+ data
40
103
  end
41
104
 
42
105
  def _url_regex
43
- /.*\.com\/(?:(?:groups\/[^\/]+\/videos\/)|(?:ondemand|channels)(?:(?:\/less\/)|(?:\/\w*\/))|(?:video\/))?([0-9]+).*$/
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
- "/api/v2/video/#{video_id}.json"
119
+ "/videos/#{video_id}"
52
120
  end
53
121
 
54
122
  def _api_url
55
- "http://#{_api_base}#{_api_path}"
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
- _playlist_video_ids.map do |entry_id|
12
- VideoInfo.new("http://vimeo.com/#{entry_id}")
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 date keywords duration view_count].each do |method|
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
- "/api/v2/album/#{video_id}/info.json"
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
- "/api/v2/album/#{video_id}/videos.json"
45
+ "/videos/#{video_id}"
40
46
  end
41
47
 
42
48
  def _api_videos_url
43
- "http://#{_api_base}#{_api_videos_path}"
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
- end
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
@@ -104,7 +104,7 @@ class VideoInfo
104
104
  ).encode(
105
105
  'UTF-8', undef: :replace
106
106
  )
107
- !!title.index('Ошибка')
107
+ !!title.index('Error | VK')
108
108
  end
109
109
 
110
110
  def _get_response_code(response)
@@ -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
- _video_thumbnail(0)
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
- _video_thumbnail(1)
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
- _video_thumbnail(2)
46
- end
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