video_info 2.5.0 → 2.6.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +3 -0
- data/README.md +9 -21
- data/foo.txt +33 -0
- data/lib/video_info.rb +17 -4
- data/lib/video_info/provider.rb +22 -1
- data/lib/video_info/providers/vimeo.rb +13 -103
- data/lib/video_info/providers/vimeo_api.rb +110 -0
- data/lib/video_info/providers/vimeo_scraper.rb +135 -0
- data/lib/video_info/providers/vkontakte.rb +15 -8
- data/lib/video_info/providers/youtube.rb +3 -6
- data/lib/video_info/providers/youtube_api.rb +3 -1
- data/lib/video_info/providers/youtube_scraper.rb +11 -15
- data/lib/video_info/providers/youtubeplaylist.rb +1 -1
- data/lib/video_info/providers/youtubeplaylist_api.rb +12 -0
- data/lib/video_info/version.rb +1 -1
- data/spec/lib/video_info/providers/vimeo_api_spec.rb +242 -0
- data/spec/lib/video_info/providers/vimeo_spec.rb +4 -4
- data/spec/lib/video_info/providers/vkontakte_spec.rb +41 -2
- data/spec/lib/video_info/providers/youtube_api_spec.rb +84 -0
- data/spec/lib/video_info/providers/youtube_playlist_api_spec.rb +15 -1
- data/spec/lib/video_info/providers/youtube_playlist_spec.rb +16 -2
- data/spec/lib/video_info/providers/youtube_spec.rb +146 -0
- data/video_info.gemspec +6 -5
- metadata +42 -26
- data/lib/video_info/providers/vimeoplaylist.rb +0 -63
- data/spec/lib/video_info/providers/vimeo_playlist_spec.rb +0 -157
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'oga'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
class VideoInfo
|
6
|
+
module Providers
|
7
|
+
module VimeoScraper
|
8
|
+
def author
|
9
|
+
json_info['author']['name']
|
10
|
+
end
|
11
|
+
|
12
|
+
def author_thumbnail
|
13
|
+
d = data.css('script')[5].text.split('window.vimeo.clip_page_config =')[1]
|
14
|
+
JSON.parse(d.split(";\n")[0])['owner']['portrait']['src']
|
15
|
+
end
|
16
|
+
|
17
|
+
def available?
|
18
|
+
is_available = super
|
19
|
+
|
20
|
+
if is_available
|
21
|
+
page_header = data.css('#page_header')
|
22
|
+
|
23
|
+
if page_header.text == "\n Private Video\n "
|
24
|
+
is_available = false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
is_available
|
29
|
+
end
|
30
|
+
|
31
|
+
def title
|
32
|
+
meta_node_value('og:title')
|
33
|
+
end
|
34
|
+
|
35
|
+
def description
|
36
|
+
meta_node_value('og:description')
|
37
|
+
end
|
38
|
+
|
39
|
+
def date
|
40
|
+
upload_date = json_info['uploadDate']
|
41
|
+
ISO8601::DateTime.new(upload_date).to_time
|
42
|
+
end
|
43
|
+
|
44
|
+
def duration
|
45
|
+
duration = json_info['duration']
|
46
|
+
ISO8601::Duration.new(duration).to_seconds.to_i
|
47
|
+
end
|
48
|
+
|
49
|
+
def keywords
|
50
|
+
keywords_str = ''
|
51
|
+
|
52
|
+
json_info['keywords'].each { |keyword| keywords_str << keyword << ", " }
|
53
|
+
|
54
|
+
keywords_str.chop.chop # remove trailing ", "
|
55
|
+
end
|
56
|
+
|
57
|
+
def height
|
58
|
+
meta_node_value('og:video:height').to_i
|
59
|
+
end
|
60
|
+
|
61
|
+
def width
|
62
|
+
meta_node_value('og:video:width').to_i
|
63
|
+
end
|
64
|
+
|
65
|
+
def thumbnail_small
|
66
|
+
thumbnail_url.split('_')[0] + '_100x75.jpg'
|
67
|
+
end
|
68
|
+
|
69
|
+
def thumbnail_medium
|
70
|
+
thumbnail_url.split('_')[0] + '_200x150.jpg'
|
71
|
+
end
|
72
|
+
|
73
|
+
def thumbnail_large
|
74
|
+
thumbnail_url.split('_')[0] + '_640.jpg'
|
75
|
+
end
|
76
|
+
|
77
|
+
def view_count
|
78
|
+
json_info['interactionCount']
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def json_info
|
84
|
+
@json_info ||= JSON.parse(data.css('script').detect do |n|
|
85
|
+
type = n.attr('type')
|
86
|
+
|
87
|
+
if type.nil?
|
88
|
+
false
|
89
|
+
else
|
90
|
+
type.value == 'application/ld+json'
|
91
|
+
end
|
92
|
+
end.text)[0]
|
93
|
+
end
|
94
|
+
|
95
|
+
def thumbnail_url
|
96
|
+
@thumbnail_url ||= json_info['thumbnailUrl']
|
97
|
+
end
|
98
|
+
|
99
|
+
def meta_nodes
|
100
|
+
@meta_nodes ||= data.css('meta')
|
101
|
+
end
|
102
|
+
|
103
|
+
def meta_node_value(name)
|
104
|
+
if available?
|
105
|
+
node = meta_nodes.detect do |n|
|
106
|
+
property = n.attr('property')
|
107
|
+
|
108
|
+
if property.nil?
|
109
|
+
false
|
110
|
+
else
|
111
|
+
property.value == name
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
node.attr('content').value
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def _set_data_from_api_impl(api_url)
|
120
|
+
Oga.parse_html(open(api_url.to_s, allow_redirections: :safe).read)
|
121
|
+
end
|
122
|
+
|
123
|
+
def _api_url
|
124
|
+
uri = URI.parse(@url)
|
125
|
+
uri.scheme = 'https'
|
126
|
+
uri.to_s
|
127
|
+
end
|
128
|
+
|
129
|
+
def _api_path
|
130
|
+
_api_url
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
@@ -50,17 +50,21 @@ class VideoInfo
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def embed_url
|
53
|
-
|
54
|
-
/iframe\ id=\"video_player\".*src=\"(
|
53
|
+
iframe_src = data[
|
54
|
+
/iframe\ id=\"video_player\".*src=\"([^\"]*)\".*frameborder=/, 1
|
55
55
|
]
|
56
|
-
if
|
56
|
+
if iframe_src
|
57
|
+
# it may be youtube video
|
57
58
|
VideoInfo::Providers::Youtube.new(
|
58
|
-
URI.unescape(
|
59
|
+
URI.unescape(iframe_src.gsub(/\\/, ''))
|
59
60
|
).embed_url
|
60
61
|
else
|
61
62
|
"//vk.com/video_ext.php?oid=#{video_owner}" +
|
62
63
|
"&id=#{video_id}&hash=#{_data_hash}"
|
63
64
|
end
|
65
|
+
rescue
|
66
|
+
# or rutube video
|
67
|
+
iframe_src
|
64
68
|
end
|
65
69
|
|
66
70
|
def duration
|
@@ -82,15 +86,14 @@ class VideoInfo
|
|
82
86
|
resp.body.force_encoding('cp1251').encode('UTF-8', undef: :replace)
|
83
87
|
end
|
84
88
|
|
85
|
-
def
|
86
|
-
url = URI('https://vk.com/al_video.php')
|
89
|
+
def _set_data_from_api_impl(api_url)
|
87
90
|
options['act'] = 'show'
|
88
91
|
options['al'] = '1'
|
89
92
|
options['video'] = "#{@video_owner}_#{@video_id}"
|
90
|
-
data = _make_request(
|
93
|
+
data = _make_request(api_url, options)
|
91
94
|
if data.index('Ошибка доступа')
|
92
95
|
# try second time
|
93
|
-
_make_request(
|
96
|
+
_make_request(api_url, options)
|
94
97
|
else
|
95
98
|
data
|
96
99
|
end
|
@@ -158,6 +161,10 @@ class VideoInfo
|
|
158
161
|
def _default_url_attributes
|
159
162
|
{}
|
160
163
|
end
|
164
|
+
|
165
|
+
def _api_url
|
166
|
+
URI('https://vk.com/al_video.php')
|
167
|
+
end
|
161
168
|
end
|
162
169
|
end
|
163
170
|
end
|
@@ -32,18 +32,15 @@ class VideoInfo
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def thumbnail_small
|
35
|
-
|
36
|
-
_video_snippet['thumbnails']['default']['url']
|
35
|
+
"https://i.ytimg.com/vi/#{video_id}/default.jpg"
|
37
36
|
end
|
38
37
|
|
39
38
|
def thumbnail_medium
|
40
|
-
|
41
|
-
_video_snippet['thumbnails']['medium']['url']
|
39
|
+
"https://i.ytimg.com/vi/#{video_id}/mqdefault.jpg"
|
42
40
|
end
|
43
41
|
|
44
42
|
def thumbnail_large
|
45
|
-
|
46
|
-
_video_snippet['thumbnails']['high']['url']
|
43
|
+
"https://i.ytimg.com/vi/#{video_id}/hqdefault.jpg"
|
47
44
|
end
|
48
45
|
|
49
46
|
private
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'oga'
|
2
2
|
require 'open-uri'
|
3
|
+
require 'net_http_timeout_errors'
|
3
4
|
|
4
5
|
class VideoInfo
|
5
6
|
module Providers
|
@@ -34,20 +35,8 @@ class VideoInfo
|
|
34
35
|
meta_node_value('title')
|
35
36
|
end
|
36
37
|
|
37
|
-
def thumbnail_small
|
38
|
-
"https://i.ytimg.com/vi/#{video_id}/default.jpg"
|
39
|
-
end
|
40
|
-
|
41
|
-
def thumbnail_medium
|
42
|
-
"https://i.ytimg.com/vi/#{video_id}/mqdefault.jpg"
|
43
|
-
end
|
44
|
-
|
45
|
-
def thumbnail_large
|
46
|
-
"https://i.ytimg.com/vi/#{video_id}/hqdefault.jpg"
|
47
|
-
end
|
48
|
-
|
49
38
|
def view_count
|
50
|
-
data.css('div.watch-view-count').text.gsub(
|
39
|
+
data.css('div.watch-view-count').text.gsub(/\D/, '').to_i
|
51
40
|
end
|
52
41
|
|
53
42
|
private
|
@@ -80,7 +69,7 @@ class VideoInfo
|
|
80
69
|
data.css('div#unavailable-submessage').text.strip.empty?
|
81
70
|
end
|
82
71
|
|
83
|
-
def
|
72
|
+
def _set_data_from_api_impl(api_url)
|
84
73
|
uri = URI(api_url)
|
85
74
|
|
86
75
|
unless uri.scheme
|
@@ -88,7 +77,14 @@ class VideoInfo
|
|
88
77
|
uri.scheme = 'http'
|
89
78
|
end
|
90
79
|
|
91
|
-
|
80
|
+
# handle fullscreen video URLs
|
81
|
+
if url.include?('.com/v/')
|
82
|
+
video_id = url.split('/v/')[1].split('?')[0]
|
83
|
+
new_url = 'https://www.youtube.com/watch?v=' + video_id
|
84
|
+
Oga.parse_html(open(new_url).read)
|
85
|
+
else
|
86
|
+
Oga.parse_html(open(uri.to_s, allow_redirections: :safe).read)
|
87
|
+
end
|
92
88
|
end
|
93
89
|
|
94
90
|
def _api_url
|
@@ -48,7 +48,7 @@ class VideoInfo
|
|
48
48
|
private
|
49
49
|
|
50
50
|
def _url_regex
|
51
|
-
/youtube.com\/playlist\?p=(\S*)|youtube.com\/embed\/videoseries\?list=([a-zA-Z0-9-]*)/
|
51
|
+
/youtube.com\/playlist\?p=(\S*)|youtube.com\/playlist\?list=(\S*)|youtube.com\/embed\/videoseries\?list=([a-zA-Z0-9-]*)/
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
@@ -22,6 +22,18 @@ class VideoInfo
|
|
22
22
|
nil
|
23
23
|
end
|
24
24
|
|
25
|
+
def thumbnail_small
|
26
|
+
_video_snippet['thumbnails']['default']['url']
|
27
|
+
end
|
28
|
+
|
29
|
+
def thumbnail_medium
|
30
|
+
_video_snippet['thumbnails']['medium']['url']
|
31
|
+
end
|
32
|
+
|
33
|
+
def thumbnail_large
|
34
|
+
_video_snippet['thumbnails']['high']['url']
|
35
|
+
end
|
36
|
+
|
25
37
|
private
|
26
38
|
|
27
39
|
def _playlist_entry
|
data/lib/video_info/version.rb
CHANGED
@@ -0,0 +1,242 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe VideoInfo::Providers::Vimeo do
|
4
|
+
before(:all) do
|
5
|
+
VideoInfo.provider_api_keys = { vimeo: '6b66b015a3504793b4f541d878f46ff6' }
|
6
|
+
end
|
7
|
+
|
8
|
+
describe '.usable?' do
|
9
|
+
subject { VideoInfo::Providers::Vimeo.usable?(url) }
|
10
|
+
|
11
|
+
context 'with vimeo url' do
|
12
|
+
let(:url) { 'http://www.vimeo.com/898029' }
|
13
|
+
it { is_expected.to be_truthy }
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'with Vimeo OnDemand url' do
|
17
|
+
let(:url) { 'https://vimeo.com/ondemand/less/101677664' }
|
18
|
+
it { is_expected.to be_truthy }
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'with Vimeo Channels url' do
|
22
|
+
let(:url) { 'https://vimeo.com/channels/any_channel/111431415' }
|
23
|
+
it { is_expected.to be_truthy }
|
24
|
+
end
|
25
|
+
|
26
|
+
context "with Vimeo Review url" do
|
27
|
+
let(:url) { 'https://vimeo.com/user39798190/review/126641548/8a56234e32' }
|
28
|
+
it { is_expected.to be_truthy }
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'with vimeo album url' do
|
32
|
+
let(:url) { 'http://vimeo.com/album/2755718' }
|
33
|
+
it { is_expected.to be_falsey }
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'with vimeo hubnub embed url' do
|
37
|
+
let(:url) { 'http://player.vimeo.com/hubnut/album/2755718' }
|
38
|
+
it { is_expected.to be_falsey }
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'with other url' do
|
42
|
+
let(:url) { 'http://www.youtube.com/898029' }
|
43
|
+
it { is_expected.to be_falsey }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#available?' do
|
48
|
+
context 'with valid video', :vcr do
|
49
|
+
subject { VideoInfo.new('http://www.vimeo.com/898029') }
|
50
|
+
|
51
|
+
describe '#available?' do
|
52
|
+
it { is_expected.to be_available }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "with 'this video does not exist' video", :vcr do
|
57
|
+
subject { VideoInfo.new('http://vimeo.com/59312311') }
|
58
|
+
|
59
|
+
describe '#available?' do
|
60
|
+
it { is_expected.to_not be_available }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context "with 'password required' video", :vcr do
|
65
|
+
subject { VideoInfo.new('http://vimeo.com/74636562') }
|
66
|
+
|
67
|
+
describe '#available?' do
|
68
|
+
it { is_expected.to_not be_available }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'with video 898029', :vcr do
|
74
|
+
subject { VideoInfo.new('http://www.vimeo.com/898029') }
|
75
|
+
|
76
|
+
describe '#provider' do
|
77
|
+
subject { super().provider }
|
78
|
+
it { is_expected.to eq 'Vimeo' }
|
79
|
+
end
|
80
|
+
|
81
|
+
describe '#video_id' do
|
82
|
+
subject { super().video_id }
|
83
|
+
it { is_expected.to eq '898029' }
|
84
|
+
end
|
85
|
+
|
86
|
+
describe '#url' do
|
87
|
+
subject { super().url }
|
88
|
+
it { is_expected.to eq 'http://www.vimeo.com/898029' }
|
89
|
+
end
|
90
|
+
|
91
|
+
describe '#embed_url' do
|
92
|
+
subject { super().embed_url }
|
93
|
+
it { is_expected.to eq '//player.vimeo.com/video/898029' }
|
94
|
+
end
|
95
|
+
|
96
|
+
describe '#embed_code' do
|
97
|
+
subject { super().embed_code }
|
98
|
+
it { is_expected.to eq '<iframe src="//player.vimeo.com/video/898029?autoplay=0&byline=0&portrait=0&title=0" frameborder="0"></iframe>' }
|
99
|
+
end
|
100
|
+
|
101
|
+
describe '#title' do
|
102
|
+
subject { super().title }
|
103
|
+
it { is_expected.to eq 'Cherry Bloom - King Of The Knife' }
|
104
|
+
end
|
105
|
+
|
106
|
+
describe '#description' do
|
107
|
+
subject { super().description }
|
108
|
+
it { is_expected.to eq 'The first video from the upcoming album Secret Sounds, to download in-stores April 14. Checkout http://www.cherrybloom.net' }
|
109
|
+
end
|
110
|
+
|
111
|
+
describe '#keywords' do
|
112
|
+
subject { super().keywords }
|
113
|
+
it { is_expected.to eq 'cherry bloom, secret sounds, king of the knife, rock, alternative' }
|
114
|
+
end
|
115
|
+
|
116
|
+
describe '#duration' do
|
117
|
+
subject { super().duration }
|
118
|
+
it { is_expected.to eq 175 }
|
119
|
+
end
|
120
|
+
|
121
|
+
describe '#width' do
|
122
|
+
subject { super().width }
|
123
|
+
it { is_expected.to eq 640 }
|
124
|
+
end
|
125
|
+
|
126
|
+
describe '#height' do
|
127
|
+
subject { super().height }
|
128
|
+
it { is_expected.to eq 360 }
|
129
|
+
end
|
130
|
+
|
131
|
+
describe '#date' do
|
132
|
+
subject { super().date }
|
133
|
+
it { is_expected.to eq Time.parse('2008-04-14T17:10:39+00:00', Time.now.utc).utc }
|
134
|
+
end
|
135
|
+
|
136
|
+
describe '#thumbnail_small' do
|
137
|
+
subject { super().thumbnail_small }
|
138
|
+
it { is_expected.to eq 'https://i.vimeocdn.com/video/34373130_100x75.jpg' }
|
139
|
+
end
|
140
|
+
|
141
|
+
describe '#thumbnail_medium' do
|
142
|
+
subject { super().thumbnail_medium }
|
143
|
+
it { is_expected.to eq 'https://i.vimeocdn.com/video/34373130_200x150.jpg' }
|
144
|
+
end
|
145
|
+
|
146
|
+
describe '#thumbnail_large' do
|
147
|
+
subject { super().thumbnail_large }
|
148
|
+
it { is_expected.to eq 'https://i.vimeocdn.com/video/34373130_640.jpg' }
|
149
|
+
end
|
150
|
+
|
151
|
+
describe '#author_thumbnail' do
|
152
|
+
subject { super().author_thumbnail }
|
153
|
+
it { is_expected.to eq 'https://i.vimeocdn.com/portrait/2577152_75x75.jpg' }
|
154
|
+
end
|
155
|
+
|
156
|
+
describe '#author' do
|
157
|
+
subject { super().author }
|
158
|
+
it { is_expected.to eq 'Octave Zangs' }
|
159
|
+
end
|
160
|
+
|
161
|
+
describe '#view_count' do
|
162
|
+
subject { super().view_count }
|
163
|
+
it { is_expected.to be > 4000 }
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context 'with video 898029 and url_attributes', :vcr do
|
168
|
+
subject { VideoInfo.new('http://www.vimeo.com/898029') }
|
169
|
+
|
170
|
+
it { expect(subject.embed_code(url_attributes: { autoplay: 1 })).to match(/autoplay=1/) }
|
171
|
+
end
|
172
|
+
|
173
|
+
context 'with video 898029 and iframe_attributes', :vcr do
|
174
|
+
subject { VideoInfo.new('http://www.vimeo.com/898029') }
|
175
|
+
|
176
|
+
it { expect(subject.embed_code(iframe_attributes: { width: 800, height: 600 })).to match(/width="800"/) }
|
177
|
+
it { expect(subject.embed_code(iframe_attributes: { width: 800, height: 600 })).to match(/height="600"/) }
|
178
|
+
end
|
179
|
+
|
180
|
+
context 'with video 898029 in /group/ url', :vcr do
|
181
|
+
subject { VideoInfo.new('http://vimeo.com/groups/1234/videos/898029') }
|
182
|
+
|
183
|
+
describe '#provider' do
|
184
|
+
subject { super().provider }
|
185
|
+
it { is_expected.to eq 'Vimeo' }
|
186
|
+
end
|
187
|
+
|
188
|
+
describe '#video_id' do
|
189
|
+
subject { super().video_id }
|
190
|
+
it { is_expected.to eq '898029' }
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
context 'with video 898029 in /group/ url', :vcr do
|
195
|
+
subject { VideoInfo.new('http://player.vimeo.com/video/898029') }
|
196
|
+
|
197
|
+
describe '#provider' do
|
198
|
+
subject { super().provider }
|
199
|
+
it { is_expected.to eq 'Vimeo' }
|
200
|
+
end
|
201
|
+
|
202
|
+
describe '#video_id' do
|
203
|
+
subject { super().video_id }
|
204
|
+
it { is_expected.to eq '898029' }
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
context 'with video 898029 in text', :vcr do
|
209
|
+
subject { VideoInfo.new('<a href="http://www.vimeo.com/898029">http://www.vimeo.com/898029</a>') }
|
210
|
+
|
211
|
+
describe '#provider' do
|
212
|
+
subject { super().provider }
|
213
|
+
it { is_expected.to eq 'Vimeo' }
|
214
|
+
end
|
215
|
+
|
216
|
+
describe '#video_id' do
|
217
|
+
subject { super().video_id }
|
218
|
+
it { is_expected.to eq '898029' }
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
context 'with video 101677664 in /ondemand/ url', :vcr do
|
223
|
+
subject { VideoInfo.new('https://vimeo.com/ondemand/less/101677664') }
|
224
|
+
|
225
|
+
its(:provider) { should eq 'Vimeo' }
|
226
|
+
its(:video_id) { should eq '101677664' }
|
227
|
+
end
|
228
|
+
|
229
|
+
context 'with video 111431415 in /channels/*/ url', :vcr do
|
230
|
+
subject { VideoInfo.new('https://vimeo.com/channels/some_channel1/111431415') }
|
231
|
+
|
232
|
+
its(:provider) { should eq 'Vimeo' }
|
233
|
+
its(:video_id) { should eq '111431415' }
|
234
|
+
end
|
235
|
+
|
236
|
+
context "with video 126641548 in /user*/review/126641548/* url", :vcr do
|
237
|
+
subject { VideoInfo.new('http://www.vimeo.com/user39798190/review/126641548/8a56234e32') }
|
238
|
+
|
239
|
+
its(:provider) { should eq 'Vimeo' }
|
240
|
+
its(:video_id) { should eq '126641548' }
|
241
|
+
end
|
242
|
+
end
|