yt-andrewroth 0.25.5.2 → 0.25.10.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +29 -0
- data/lib/yt/collections/content_details.rb +3 -2
- data/lib/yt/collections/playlist_items.rb +1 -1
- data/lib/yt/collections/reports.rb +1 -0
- data/lib/yt/models/channel.rb +6 -0
- data/lib/yt/models/content_detail.rb +1 -0
- data/lib/yt/models/playlist.rb +8 -0
- data/lib/yt/models/url.rb +1 -0
- data/lib/yt/models/video.rb +6 -0
- data/lib/yt/request.rb +12 -3
- data/lib/yt/version.rb +1 -1
- data/spec/models/request_spec.rb +20 -0
- data/spec/models/url_spec.rb +6 -0
- data/spec/requests/as_account/channel_spec.rb +4 -0
- data/spec/requests/as_account/playlist_spec.rb +1 -0
- data/spec/requests/as_account/video_spec.rb +4 -0
- data/spec/requests/as_content_owner/channel_spec.rb +113 -0
- data/spec/requests/as_content_owner/video_spec.rb +46 -0
- data/spec/requests/as_server_app/playlist_spec.rb +1 -0
- metadata +95 -116
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a5df5eb1c5d30ee68dad95aae24a2d8dc3561496
|
4
|
+
data.tar.gz: eca61399f1d812d4da9cbe7a27c744ad01bf826f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3e98e393397705fbabb1263ad4cc187f5ffc3a3259876e8f7aaad7b4f8db898af18cc61e2cc36934cc09851020300c0674812982c11393733a71c45f35aa09c4
|
7
|
+
data.tar.gz: 78c8edfbc28d05229149002cd97804bab152b5bdc417592bbb47ea4f1bc5bf4b30101e506068b4ae59abf74c0002f302db3f73f8262afe3179c02ed80363b9b0
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,35 @@ For more information about changelogs, check
|
|
6
6
|
[Keep a Changelog](http://keepachangelog.com) and
|
7
7
|
[Vandamme](http://tech-angels.github.io/vandamme).
|
8
8
|
|
9
|
+
-## 0.25.11.2 - 2015-11-05
|
10
|
+
|
11
|
+
* Never cache attributes
|
12
|
+
|
13
|
+
-## 0.25.11 - 2015-11-05
|
14
|
+
|
15
|
+
* [ENHANCEMENT] Add "youtube.com/v/..." as possible URL for YouTube videos
|
16
|
+
* [ENHANCEMENT] Add eager loading to channel.playlists
|
17
|
+
|
18
|
+
## 0.25.10 - 2015-10-29
|
19
|
+
|
20
|
+
* [FEATURE] Add Playlist#item_count
|
21
|
+
|
22
|
+
## 0.25.9 - 2015-10-07
|
23
|
+
|
24
|
+
* [ENHANCEMENT] Add newly available traffic source: "Playlist page"
|
25
|
+
|
26
|
+
## 0.25.8 - 2015-09-10
|
27
|
+
|
28
|
+
* [FEATURE] Retry the same request up to 3 times if YouTube responds with "quotaExceeded"
|
29
|
+
|
30
|
+
## 0.25.7 - 2015-09-10
|
31
|
+
|
32
|
+
* [FEATURE] Retry the same request once if YouTube responds with "quotaExceeded"
|
33
|
+
|
34
|
+
## 0.25.6 - 2015-09-03
|
35
|
+
|
36
|
+
* [FEATURE] New channel/video reports: `videos_added_to_playlists`, `videos_removed_from_playlists`.
|
37
|
+
|
9
38
|
## 0.25.5 - 2015-08-12
|
10
39
|
|
11
40
|
* [BUGIX] Correctly parse the YouTube response when requesting a refresh token with the wrong credentials.
|
@@ -16,9 +16,10 @@ module Yt
|
|
16
16
|
# content detail of a resource, for instance a video.
|
17
17
|
# @see https://developers.google.com/youtube/v3/docs/videos#resource
|
18
18
|
def list_params
|
19
|
+
endpoint = @parent.kind.pluralize.camelize :lower
|
19
20
|
super.tap do |params|
|
20
21
|
params[:params] = content_details_params
|
21
|
-
params[:path] =
|
22
|
+
params[:path] = "/youtube/v3/#{endpoint}"
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
@@ -27,4 +28,4 @@ module Yt
|
|
27
28
|
end
|
28
29
|
end
|
29
30
|
end
|
30
|
-
end
|
31
|
+
end
|
@@ -25,7 +25,7 @@ module Yt
|
|
25
25
|
if included_relationships.include?(:video)
|
26
26
|
video_ids = items.map{|item| item['snippet']['resourceId']['videoId']}.uniq
|
27
27
|
conditions = {id: video_ids.join(',')}
|
28
|
-
conditions[:part] = 'snippet,status,statistics'
|
28
|
+
conditions[:part] = 'snippet,status,statistics,contentDetails'
|
29
29
|
videos = Collections::Videos.new(auth: @auth).where conditions
|
30
30
|
items.each do |item|
|
31
31
|
video = videos.find{|v| v.id == item['snippet']['resourceId']['videoId']}
|
data/lib/yt/models/channel.rb
CHANGED
@@ -147,6 +147,12 @@ module Yt
|
|
147
147
|
# @macro report_by_day_and_country
|
148
148
|
has_report :favorites_removed, Integer
|
149
149
|
|
150
|
+
# @macro report_by_day_and_country
|
151
|
+
has_report :videos_added_to_playlists, Integer
|
152
|
+
|
153
|
+
# @macro report_by_day_and_country
|
154
|
+
has_report :videos_removed_from_playlists, Integer
|
155
|
+
|
150
156
|
# @macro report_by_day_and_state
|
151
157
|
has_report :average_view_duration, Integer
|
152
158
|
|
data/lib/yt/models/playlist.rb
CHANGED
@@ -41,6 +41,14 @@ module Yt
|
|
41
41
|
# @return [Array<String>] the list of tags attached to the playlist.
|
42
42
|
delegate :tags, to: :snippet
|
43
43
|
|
44
|
+
### STATISTICS ###
|
45
|
+
|
46
|
+
has_one :content_detail
|
47
|
+
|
48
|
+
# @!attribute [r] item_count
|
49
|
+
# @return [Integer] the number of items in the playlist.
|
50
|
+
delegate :item_count, to: :content_detail
|
51
|
+
|
44
52
|
### ACTIONS (UPLOAD, UPDATE, DELETE) ###
|
45
53
|
|
46
54
|
# Deletes the playlist.
|
data/lib/yt/models/url.rb
CHANGED
data/lib/yt/models/video.rb
CHANGED
@@ -420,6 +420,12 @@ module Yt
|
|
420
420
|
# @macro report_by_day_and_country
|
421
421
|
has_report :favorites_removed, Integer
|
422
422
|
|
423
|
+
# @macro report_by_day_and_country
|
424
|
+
has_report :videos_added_to_playlists, Integer
|
425
|
+
|
426
|
+
# @macro report_by_day_and_country
|
427
|
+
has_report :videos_removed_from_playlists, Integer
|
428
|
+
|
423
429
|
# @macro report_by_day_and_state
|
424
430
|
has_report :average_view_duration, Integer
|
425
431
|
|
data/lib/yt/request.rb
CHANGED
@@ -188,13 +188,17 @@ module Yt
|
|
188
188
|
end
|
189
189
|
|
190
190
|
# Returns whether it is worth to run a failed request again.
|
191
|
-
# There are
|
191
|
+
# There are three cases in which retrying a request might be worth:
|
192
192
|
# - when the server specifies that the request token has expired and
|
193
|
-
# the user has to refresh the token in order to
|
193
|
+
# the user has to refresh the token in order to try again
|
194
194
|
# - when the server is unreachable, and waiting for a couple of seconds
|
195
195
|
# might solve the connection issues.
|
196
|
+
# - when the user has reached the quota for requests/second, and waiting
|
197
|
+
# for a couple of seconds might solve the connection issues.
|
196
198
|
def run_again?
|
197
|
-
refresh_token_and_retry? ||
|
199
|
+
refresh_token_and_retry? ||
|
200
|
+
server_error? && sleep_and_retry? ||
|
201
|
+
exceeded_quota? && sleep_and_retry?(3)
|
198
202
|
end
|
199
203
|
|
200
204
|
# Returns the list of server errors worth retrying the request once.
|
@@ -261,6 +265,11 @@ module Yt
|
|
261
265
|
response_error == Errors::ServerError
|
262
266
|
end
|
263
267
|
|
268
|
+
# @return [Boolean] whether the request exceeds the YouTube quota
|
269
|
+
def exceeded_quota?
|
270
|
+
response_error == Errors::Forbidden && response.body =~ /quotaExceeded/
|
271
|
+
end
|
272
|
+
|
264
273
|
# @return [Boolean] whether the request lacks proper authorization.
|
265
274
|
def unauthorized?
|
266
275
|
response_error == Errors::Unauthorized
|
data/lib/yt/version.rb
CHANGED
data/spec/models/request_spec.rb
CHANGED
@@ -37,6 +37,26 @@ describe Yt::Request do
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
+
context 'an error code 403 with a "quota exceeded message"' do
|
41
|
+
let(:response_class) { Net::HTTPForbidden }
|
42
|
+
let(:retry_response) { retry_response_class.new nil, nil, nil }
|
43
|
+
let(:response_body) { "{\n \"error\": {\n \"errors\": [\n {\n \"domain\": \"youtube.quota\",\n \"reason\": \"quotaExceeded\",\n \"message\": \"The request cannot be completed because you have exceeded your \\u003ca href=\\\"/youtube/v3/getting-started#quota\\\"\\u003equota\\u003c/a\\u003e.\"\n }\n ],\n \"code\": 403,\n \"message\": \"The request cannot be completed because you have exceeded your \\u003ca href=\\\"/youtube/v3/getting-started#quota\\\"\\u003equota\\u003c/a\\u003e.\"\n }\n}\n" }
|
44
|
+
before { allow(retry_response).to receive(:body) }
|
45
|
+
before { expect(Net::HTTP).to receive(:start).at_least(:once).and_return retry_response }
|
46
|
+
|
47
|
+
context 'every time' do
|
48
|
+
let(:retry_response_class) { Net::HTTPForbidden }
|
49
|
+
|
50
|
+
it { expect{request.run}.to fail }
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'but returns a success code 2XX the second time' do
|
54
|
+
let(:retry_response_class) { Net::HTTPOK }
|
55
|
+
|
56
|
+
it { expect{request.run}.not_to fail }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
40
60
|
context 'an error code 401' do
|
41
61
|
let(:response_class) { Net::HTTPUnauthorized }
|
42
62
|
|
data/spec/models/url_spec.rb
CHANGED
@@ -25,6 +25,12 @@ describe Yt::URL do
|
|
25
25
|
it {expect(url.id).to eq 'MESycYJytkU' }
|
26
26
|
end
|
27
27
|
|
28
|
+
context 'given a v video URL' do
|
29
|
+
let(:text) { 'https://www.youtube.com/v/MESycYJytkU' }
|
30
|
+
it {expect(url.kind).to eq :video }
|
31
|
+
it {expect(url.id).to eq 'MESycYJytkU' }
|
32
|
+
end
|
33
|
+
|
28
34
|
context 'given a playlist-embedded video URL' do
|
29
35
|
let(:text) { 'youtube.com/watch?v=MESycYJytkU&list=LLxO1tY8h1AhOz0T4ENwmpow' }
|
30
36
|
it {expect(url.kind).to eq :video }
|
@@ -204,6 +204,8 @@ describe Yt::Channel, :device_app do
|
|
204
204
|
expect{channel.subscribers_lost}.not_to raise_error
|
205
205
|
expect{channel.favorites_added}.not_to raise_error
|
206
206
|
expect{channel.favorites_removed}.not_to raise_error
|
207
|
+
expect{channel.videos_added_to_playlists}.not_to raise_error
|
208
|
+
expect{channel.videos_removed_from_playlists}.not_to raise_error
|
207
209
|
expect{channel.estimated_minutes_watched}.not_to raise_error
|
208
210
|
expect{channel.average_view_duration}.not_to raise_error
|
209
211
|
expect{channel.average_view_percentage}.not_to raise_error
|
@@ -225,6 +227,8 @@ describe Yt::Channel, :device_app do
|
|
225
227
|
expect{channel.subscribers_lost_on 3.days.ago}.not_to raise_error
|
226
228
|
expect{channel.favorites_added_on 3.days.ago}.not_to raise_error
|
227
229
|
expect{channel.favorites_removed_on 3.days.ago}.not_to raise_error
|
230
|
+
expect{channel.videos_added_to_playlists_on 3.days.ago}.not_to raise_error
|
231
|
+
expect{channel.videos_removed_from_playlists_on 3.days.ago}.not_to raise_error
|
228
232
|
expect{channel.estimated_minutes_watched_on 3.days.ago}.not_to raise_error
|
229
233
|
expect{channel.average_view_duration_on 3.days.ago}.not_to raise_error
|
230
234
|
expect{channel.average_view_percentage_on 3.days.ago}.not_to raise_error
|
@@ -18,6 +18,7 @@ describe Yt::Playlist, :device_app do
|
|
18
18
|
expect(playlist.channel_id).to be_a String
|
19
19
|
expect(playlist.channel_title).to be_a String
|
20
20
|
expect(playlist.privacy_status).to be_a String
|
21
|
+
expect(playlist.item_count).to be_an Integer
|
21
22
|
end
|
22
23
|
|
23
24
|
describe '.playlist_items' do
|
@@ -292,6 +292,8 @@ describe Yt::Video, :device_app do
|
|
292
292
|
expect{video.subscribers_lost}.not_to raise_error
|
293
293
|
expect{video.favorites_added}.not_to raise_error
|
294
294
|
expect{video.favorites_removed}.not_to raise_error
|
295
|
+
expect{video.videos_added_to_playlists}.not_to raise_error
|
296
|
+
expect{video.videos_removed_from_playlists}.not_to raise_error
|
295
297
|
expect{video.estimated_minutes_watched}.not_to raise_error
|
296
298
|
expect{video.average_view_duration}.not_to raise_error
|
297
299
|
expect{video.average_view_percentage}.not_to raise_error
|
@@ -314,6 +316,8 @@ describe Yt::Video, :device_app do
|
|
314
316
|
expect{video.subscribers_lost_on 3.days.ago}.not_to raise_error
|
315
317
|
expect{video.favorites_added_on 3.days.ago}.not_to raise_error
|
316
318
|
expect{video.favorites_removed_on 3.days.ago}.not_to raise_error
|
319
|
+
expect{video.videos_added_to_playlists_on 3.days.ago}.not_to raise_error
|
320
|
+
expect{video.videos_removed_from_playlists_on 3.days.ago}.not_to raise_error
|
317
321
|
expect{video.estimated_minutes_watched_on 3.days.ago}.not_to raise_error
|
318
322
|
expect{video.average_view_duration_on 3.days.ago}.not_to raise_error
|
319
323
|
expect{video.average_view_percentage_on 3.days.ago}.not_to raise_error
|
@@ -15,6 +15,7 @@ describe Yt::Channel, :partner do
|
|
15
15
|
estimated_minutes_watched: Integer, comments: Integer, likes: Integer,
|
16
16
|
dislikes: Integer, shares: Integer, subscribers_gained: Integer,
|
17
17
|
subscribers_lost: Integer, favorites_added: Integer,
|
18
|
+
videos_added_to_playlists: Integer, videos_removed_from_playlists: Integer,
|
18
19
|
favorites_removed: Integer, average_view_duration: Integer,
|
19
20
|
average_view_percentage: Float, annotation_clicks: Integer,
|
20
21
|
annotation_click_through_rate: Float,
|
@@ -58,6 +59,7 @@ describe Yt::Channel, :partner do
|
|
58
59
|
|
59
60
|
[:views, :uniques, :comments, :likes, :dislikes, :shares,
|
60
61
|
:subscribers_gained, :subscribers_lost, :favorites_added,
|
62
|
+
:videos_added_to_playlists, :videos_removed_from_playlists,
|
61
63
|
:favorites_removed, :estimated_minutes_watched, :average_view_duration,
|
62
64
|
:average_view_percentage, :impressions, :monetized_playbacks,
|
63
65
|
:annotation_clicks, :annotation_click_through_rate, :playback_based_cpm,
|
@@ -117,6 +119,7 @@ describe Yt::Channel, :partner do
|
|
117
119
|
estimated_minutes_watched: Integer, average_view_duration: Integer,
|
118
120
|
annotation_clicks: Integer, annotation_click_through_rate: Float,
|
119
121
|
favorites_added: Integer, favorites_removed: Integer,
|
122
|
+
videos_added_to_playlists: Integer, videos_removed_from_playlists: Integer,
|
120
123
|
average_view_percentage: Float, impressions: Integer,
|
121
124
|
shares: Integer, playback_based_cpm: Float,
|
122
125
|
monetized_playbacks: Integer, annotation_close_rate: Float,
|
@@ -983,6 +986,116 @@ describe Yt::Channel, :partner do
|
|
983
986
|
end
|
984
987
|
end
|
985
988
|
|
989
|
+
describe 'videos added to playlists can be retrieved for a single country' do
|
990
|
+
let(:country_code) { 'US' }
|
991
|
+
let(:videos_added_to_playlists) { channel.videos_added_to_playlists since: date, by: by, in: location }
|
992
|
+
let(:date) { ENV['YT_TEST_PARTNER_VIDEO_DATE'] }
|
993
|
+
|
994
|
+
context 'and grouped by day' do
|
995
|
+
let(:by) { :day }
|
996
|
+
|
997
|
+
context 'with the :in option set to the country code' do
|
998
|
+
let(:location) { country_code }
|
999
|
+
it { expect(videos_added_to_playlists.keys.min).to eq date.to_date }
|
1000
|
+
end
|
1001
|
+
|
1002
|
+
context 'with the :in option set to {country: country code}' do
|
1003
|
+
let(:location) { {country: country_code} }
|
1004
|
+
it { expect(videos_added_to_playlists.keys.min).to eq date.to_date }
|
1005
|
+
end
|
1006
|
+
end
|
1007
|
+
|
1008
|
+
context 'and grouped by country' do
|
1009
|
+
let(:by) { :country }
|
1010
|
+
|
1011
|
+
context 'with the :in option set to the country code' do
|
1012
|
+
let(:location) { country_code }
|
1013
|
+
it { expect(videos_added_to_playlists.keys).to eq [country_code] }
|
1014
|
+
end
|
1015
|
+
|
1016
|
+
context 'with the :in option set to {country: country code}' do
|
1017
|
+
let(:location) { {country: country_code} }
|
1018
|
+
it { expect(videos_added_to_playlists.keys).to eq [country_code] }
|
1019
|
+
end
|
1020
|
+
end
|
1021
|
+
end
|
1022
|
+
|
1023
|
+
describe 'added favorites can be grouped by day' do
|
1024
|
+
let(:range) { {since: 4.days.ago.to_date, until: 3.days.ago.to_date} }
|
1025
|
+
let(:keys) { range.values }
|
1026
|
+
|
1027
|
+
specify 'with the :by option set to :day' do
|
1028
|
+
videos_added_to_playlists = channel.videos_added_to_playlists range.merge by: :day
|
1029
|
+
expect(videos_added_to_playlists.keys).to eq range.values
|
1030
|
+
end
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
describe 'added favorites can be grouped by country' do
|
1034
|
+
let(:range) { {since: 4.days.ago, until: 3.days.ago} }
|
1035
|
+
|
1036
|
+
specify 'with the :by option set to :country' do
|
1037
|
+
videos_added_to_playlists = channel.videos_added_to_playlists range.merge by: :country
|
1038
|
+
expect(videos_added_to_playlists.keys).to all(be_a String)
|
1039
|
+
expect(videos_added_to_playlists.keys.map(&:length).uniq).to eq [2]
|
1040
|
+
expect(videos_added_to_playlists.values).to all(be_an Integer)
|
1041
|
+
end
|
1042
|
+
end
|
1043
|
+
|
1044
|
+
describe 'videos removed from playlists can be retrieved for a single country' do
|
1045
|
+
let(:country_code) { 'US' }
|
1046
|
+
let(:videos_removed_from_playlists) { channel.videos_removed_from_playlists since: date, by: by, in: location }
|
1047
|
+
let(:date) { ENV['YT_TEST_PARTNER_VIDEO_DATE'] }
|
1048
|
+
|
1049
|
+
context 'and grouped by day' do
|
1050
|
+
let(:by) { :day }
|
1051
|
+
|
1052
|
+
context 'with the :in option set to the country code' do
|
1053
|
+
let(:location) { country_code }
|
1054
|
+
it { expect(videos_removed_from_playlists.keys.min).to eq date.to_date }
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
context 'with the :in option set to {country: country code}' do
|
1058
|
+
let(:location) { {country: country_code} }
|
1059
|
+
it { expect(videos_removed_from_playlists.keys.min).to eq date.to_date }
|
1060
|
+
end
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
context 'and grouped by country' do
|
1064
|
+
let(:by) { :country }
|
1065
|
+
|
1066
|
+
context 'with the :in option set to the country code' do
|
1067
|
+
let(:location) { country_code }
|
1068
|
+
it { expect(videos_removed_from_playlists.keys).to eq [country_code] }
|
1069
|
+
end
|
1070
|
+
|
1071
|
+
context 'with the :in option set to {country: country code}' do
|
1072
|
+
let(:location) { {country: country_code} }
|
1073
|
+
it { expect(videos_removed_from_playlists.keys).to eq [country_code] }
|
1074
|
+
end
|
1075
|
+
end
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
describe 'removed favorites can be grouped by day' do
|
1079
|
+
let(:range) { {since: 4.days.ago.to_date, until: 3.days.ago.to_date} }
|
1080
|
+
let(:keys) { range.values }
|
1081
|
+
|
1082
|
+
specify 'with the :by option set to :day' do
|
1083
|
+
videos_removed_from_playlists = channel.videos_removed_from_playlists range.merge by: :day
|
1084
|
+
expect(videos_removed_from_playlists.keys).to eq range.values
|
1085
|
+
end
|
1086
|
+
end
|
1087
|
+
|
1088
|
+
describe 'removed favorites can be grouped by country' do
|
1089
|
+
let(:range) { {since: ENV['YT_TEST_PARTNER_VIDEO_DATE'], until: Date.parse(ENV['YT_TEST_PARTNER_VIDEO_DATE']) + 5} }
|
1090
|
+
|
1091
|
+
specify 'with the :by option set to :country' do
|
1092
|
+
videos_removed_from_playlists = channel.videos_removed_from_playlists range.merge by: :country
|
1093
|
+
expect(videos_removed_from_playlists.keys).to all(be_a String)
|
1094
|
+
expect(videos_removed_from_playlists.keys.map(&:length).uniq).to eq [2]
|
1095
|
+
expect(videos_removed_from_playlists.values).to all(be_an Integer)
|
1096
|
+
end
|
1097
|
+
end
|
1098
|
+
|
986
1099
|
describe 'estimated minutes watched can be retrieved for a single country' do
|
987
1100
|
let(:country_code) { 'US' }
|
988
1101
|
let(:estimated_minutes_watched) { channel.estimated_minutes_watched since: date, by: by, in: location }
|
@@ -15,6 +15,7 @@ describe Yt::Video, :partner do
|
|
15
15
|
|
16
16
|
[:views, :uniques, :comments, :likes, :dislikes, :shares,
|
17
17
|
:subscribers_gained, :subscribers_lost, :favorites_added,
|
18
|
+
:videos_added_to_playlists, :videos_removed_from_playlists,
|
18
19
|
:favorites_removed, :estimated_minutes_watched, :average_view_duration,
|
19
20
|
:average_view_percentage, :impressions, :monetized_playbacks,
|
20
21
|
:annotation_clicks, :annotation_click_through_rate, :playback_based_cpm,
|
@@ -111,6 +112,7 @@ describe Yt::Video, :partner do
|
|
111
112
|
{views: Integer, comments: Integer, likes: Integer, dislikes: Integer,
|
112
113
|
shares: Integer, subscribers_gained: Integer, subscribers_lost: Integer,
|
113
114
|
favorites_added: Integer,
|
115
|
+
videos_added_to_playlists: Integer, videos_removed_from_playlists: Integer,
|
114
116
|
estimated_minutes_watched: Integer, average_view_duration: Integer,
|
115
117
|
average_view_percentage: Float, impressions: Integer,
|
116
118
|
monetized_playbacks: Integer, annotation_clicks: Integer,
|
@@ -162,6 +164,7 @@ describe Yt::Video, :partner do
|
|
162
164
|
|
163
165
|
[:views, :comments, :likes, :dislikes, :shares,
|
164
166
|
:subscribers_gained, :subscribers_lost, :favorites_added,
|
167
|
+
:videos_added_to_playlists, :videos_removed_from_playlists,
|
165
168
|
:estimated_minutes_watched, :average_view_duration,
|
166
169
|
:average_view_percentage, :impressions, :monetized_playbacks,
|
167
170
|
:annotation_clicks, :annotation_click_through_rate,
|
@@ -211,6 +214,7 @@ describe Yt::Video, :partner do
|
|
211
214
|
estimated_minutes_watched: Integer, comments: Integer, likes: Integer,
|
212
215
|
dislikes: Integer, shares: Integer, subscribers_gained: Integer,
|
213
216
|
subscribers_lost: Integer, favorites_added: Integer,
|
217
|
+
videos_added_to_playlists: Integer, videos_removed_from_playlists: Integer,
|
214
218
|
favorites_removed: Integer, average_view_duration: Integer,
|
215
219
|
average_view_percentage: Float, annotation_clicks: Integer,
|
216
220
|
annotation_click_through_rate: Float,
|
@@ -575,6 +579,48 @@ describe Yt::Video, :partner do
|
|
575
579
|
end
|
576
580
|
end
|
577
581
|
|
582
|
+
describe 'added to playlists can be grouped by day' do
|
583
|
+
let(:range) { {since: 4.days.ago.to_date, until: 3.days.ago.to_date} }
|
584
|
+
let(:keys) { range.values }
|
585
|
+
|
586
|
+
specify 'with the :by option set to :day' do
|
587
|
+
videos_added_to_playlists = video.videos_added_to_playlists range.merge by: :day
|
588
|
+
expect(videos_added_to_playlists.keys).to eq range.values
|
589
|
+
end
|
590
|
+
end
|
591
|
+
|
592
|
+
describe 'added to playlists can be grouped by country' do
|
593
|
+
let(:range) { {since: ENV['YT_TEST_PARTNER_VIDEO_DATE']} }
|
594
|
+
|
595
|
+
specify 'with the :by option set to :country' do
|
596
|
+
videos_added_to_playlists = video.videos_added_to_playlists range.merge by: :country
|
597
|
+
expect(videos_added_to_playlists.keys).to all(be_a String)
|
598
|
+
expect(videos_added_to_playlists.keys.map(&:length).uniq).to eq [2]
|
599
|
+
expect(videos_added_to_playlists.values).to all(be_an Integer)
|
600
|
+
end
|
601
|
+
end
|
602
|
+
|
603
|
+
describe 'removed from playlists can be grouped by day' do
|
604
|
+
let(:range) { {since: 4.days.ago.to_date, until: 3.days.ago.to_date} }
|
605
|
+
let(:keys) { range.values }
|
606
|
+
|
607
|
+
specify 'with the :by option set to :day' do
|
608
|
+
videos_removed_from_playlists = video.videos_removed_from_playlists range.merge by: :day
|
609
|
+
expect(videos_removed_from_playlists.keys).to eq range.values
|
610
|
+
end
|
611
|
+
end
|
612
|
+
|
613
|
+
describe 'removed from playlists can be grouped by country' do
|
614
|
+
let(:range) { {since: ENV['YT_TEST_PARTNER_VIDEO_DATE']} }
|
615
|
+
|
616
|
+
specify 'with the :by option set to :country' do
|
617
|
+
videos_removed_from_playlists = video.videos_removed_from_playlists range.merge by: :country
|
618
|
+
expect(videos_removed_from_playlists.keys).to all(be_a String)
|
619
|
+
expect(videos_removed_from_playlists.keys.map(&:length).uniq).to eq [2]
|
620
|
+
expect(videos_removed_from_playlists.values).to all(be_an Integer)
|
621
|
+
end
|
622
|
+
end
|
623
|
+
|
578
624
|
describe 'added favorites can be grouped by day' do
|
579
625
|
let(:range) { {since: 4.days.ago.to_date, until: 3.days.ago.to_date} }
|
580
626
|
let(:keys) { range.values }
|
@@ -16,6 +16,7 @@ describe Yt::Playlist, :server_app do
|
|
16
16
|
expect(playlist.tags).to be_an Array
|
17
17
|
expect(playlist.channel_id).to be_a String
|
18
18
|
expect(playlist.channel_title).to be_a String
|
19
|
+
expect(playlist.item_count).to be_an Integer
|
19
20
|
end
|
20
21
|
|
21
22
|
it { expect(playlist.status).to be_a Yt::Status }
|
metadata
CHANGED
@@ -1,122 +1,111 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: yt-andrewroth
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 25
|
9
|
-
- 5
|
10
|
-
- 2
|
11
|
-
version: 0.25.5.2
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.25.10.2
|
12
5
|
platform: ruby
|
13
|
-
authors:
|
6
|
+
authors:
|
14
7
|
- Claudio Baccigalupo
|
15
8
|
autorequire:
|
16
9
|
bindir: bin
|
17
10
|
cert_chain: []
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
dependencies:
|
22
|
-
- !ruby/object:Gem::Dependency
|
11
|
+
date: 2015-11-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
23
14
|
name: activesupport
|
24
|
-
|
25
|
-
|
26
|
-
none: false
|
27
|
-
requirements:
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
28
17
|
- - ">="
|
29
|
-
- !ruby/object:Gem::Version
|
30
|
-
|
31
|
-
segments:
|
32
|
-
- 0
|
33
|
-
version: "0"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
34
20
|
type: :runtime
|
35
|
-
version_requirements: *id001
|
36
|
-
- !ruby/object:Gem::Dependency
|
37
|
-
name: bundler
|
38
21
|
prerelease: false
|
39
|
-
|
40
|
-
|
41
|
-
requirements:
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
42
24
|
- - ">="
|
43
|
-
- !ruby/object:Gem::Version
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
48
34
|
type: :development
|
49
|
-
version_requirements: *id002
|
50
|
-
- !ruby/object:Gem::Dependency
|
51
|
-
name: rspec
|
52
35
|
prerelease: false
|
53
|
-
|
54
|
-
|
55
|
-
requirements:
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
56
38
|
- - ">="
|
57
|
-
- !ruby/object:Gem::Version
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
62
48
|
type: :development
|
63
|
-
version_requirements: *id003
|
64
|
-
- !ruby/object:Gem::Dependency
|
65
|
-
name: rake
|
66
49
|
prerelease: false
|
67
|
-
|
68
|
-
|
69
|
-
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
70
59
|
- - ">="
|
71
|
-
- !ruby/object:Gem::Version
|
72
|
-
|
73
|
-
segments:
|
74
|
-
- 0
|
75
|
-
version: "0"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
76
62
|
type: :development
|
77
|
-
version_requirements: *id004
|
78
|
-
- !ruby/object:Gem::Dependency
|
79
|
-
name: yard
|
80
63
|
prerelease: false
|
81
|
-
|
82
|
-
|
83
|
-
requirements:
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
84
66
|
- - ">="
|
85
|
-
- !ruby/object:Gem::Version
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: yard
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
90
76
|
type: :development
|
91
|
-
version_requirements: *id005
|
92
|
-
- !ruby/object:Gem::Dependency
|
93
|
-
name: coveralls
|
94
77
|
prerelease: false
|
95
|
-
|
96
|
-
|
97
|
-
requirements:
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
98
80
|
- - ">="
|
99
|
-
- !ruby/object:Gem::Version
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: coveralls
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
104
90
|
type: :development
|
105
|
-
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
106
97
|
description: Youtube V3 API client.
|
107
|
-
email:
|
98
|
+
email:
|
108
99
|
- claudio@fullscreen.net
|
109
|
-
executables:
|
100
|
+
executables:
|
110
101
|
- yt
|
111
102
|
extensions: []
|
112
|
-
|
113
103
|
extra_rdoc_files: []
|
114
|
-
|
115
|
-
|
116
|
-
- .
|
117
|
-
- .
|
118
|
-
- .
|
119
|
-
- .yardopts
|
104
|
+
files:
|
105
|
+
- ".gitignore"
|
106
|
+
- ".rspec"
|
107
|
+
- ".travis.yml"
|
108
|
+
- ".yardopts"
|
120
109
|
- CHANGELOG.md
|
121
110
|
- Gemfile
|
122
111
|
- MIT-LICENSE
|
@@ -303,43 +292,32 @@ files:
|
|
303
292
|
- spec/support/fail_matcher.rb
|
304
293
|
- spec/support/global_hooks.rb
|
305
294
|
- yt.gemspec
|
306
|
-
has_rdoc: true
|
307
295
|
homepage: http://github.com/Fullscreen/yt
|
308
|
-
licenses:
|
296
|
+
licenses:
|
309
297
|
- MIT
|
298
|
+
metadata: {}
|
310
299
|
post_install_message:
|
311
300
|
rdoc_options: []
|
312
|
-
|
313
|
-
require_paths:
|
301
|
+
require_paths:
|
314
302
|
- lib
|
315
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
316
|
-
|
317
|
-
requirements:
|
303
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
304
|
+
requirements:
|
318
305
|
- - ">="
|
319
|
-
- !ruby/object:Gem::Version
|
320
|
-
hash: 53
|
321
|
-
segments:
|
322
|
-
- 1
|
323
|
-
- 9
|
324
|
-
- 3
|
306
|
+
- !ruby/object:Gem::Version
|
325
307
|
version: 1.9.3
|
326
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
327
|
-
|
328
|
-
requirements:
|
308
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
309
|
+
requirements:
|
329
310
|
- - ">="
|
330
|
-
- !ruby/object:Gem::Version
|
331
|
-
|
332
|
-
segments:
|
333
|
-
- 0
|
334
|
-
version: "0"
|
311
|
+
- !ruby/object:Gem::Version
|
312
|
+
version: '0'
|
335
313
|
requirements: []
|
336
|
-
|
337
314
|
rubyforge_project:
|
338
|
-
rubygems_version:
|
315
|
+
rubygems_version: 2.5.0
|
339
316
|
signing_key:
|
340
|
-
specification_version:
|
341
|
-
summary: Yt makes it easy to interact with Youtube V3 API by providing a modular,
|
342
|
-
|
317
|
+
specification_version: 4
|
318
|
+
summary: Yt makes it easy to interact with Youtube V3 API by providing a modular,
|
319
|
+
intuitive and tested Ruby-style API.
|
320
|
+
test_files:
|
343
321
|
- spec/collections/claims_spec.rb
|
344
322
|
- spec/collections/playlist_items_spec.rb
|
345
323
|
- spec/collections/playlists_spec.rb
|
@@ -414,3 +392,4 @@ test_files:
|
|
414
392
|
- spec/spec_helper.rb
|
415
393
|
- spec/support/fail_matcher.rb
|
416
394
|
- spec/support/global_hooks.rb
|
395
|
+
has_rdoc:
|