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.
@@ -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
@@ -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] = '/youtube/v3/videos'
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']}
@@ -42,6 +42,7 @@ module Yt
42
42
  search: 'YT_SEARCH',
43
43
  google: 'GOOGLE_SEARCH',
44
44
  notification: 'NOTIFICATION',
45
+ playlist_page: 'YT_PLAYLIST_PAGE',
45
46
  info_card: 'INFO_CARD'
46
47
  }
47
48
 
@@ -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
 
@@ -23,6 +23,7 @@ module Yt
23
23
  has_attribute :caption
24
24
  has_attribute :licensed_content
25
25
  has_attribute :content_rating, default: {}
26
+ has_attribute :item_count
26
27
 
27
28
  def youtube_rating
28
29
  content_rating['ytRating']
@@ -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.
@@ -72,6 +72,7 @@ module Yt
72
72
  youtube\\.com/watch\\?v=#{video_id}
73
73
  youtu\\.be/#{video_id}
74
74
  youtube\\.com/embed/#{video_id}
75
+ youtube\\.com/v/#{video_id}
75
76
  }
76
77
  end
77
78
 
@@ -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
 
@@ -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 two cases in which retrying a request might be worth:
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 tryi again
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? || server_error? && sleep_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
@@ -1,3 +1,3 @@
1
1
  module Yt
2
- VERSION = '0.25.5.2'
2
+ VERSION = '0.25.10.2'
3
3
  end
@@ -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
 
@@ -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
- hash: 151
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
- date: 2015-08-13 00:00:00 -04:00
20
- default_executable:
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
- prerelease: false
25
- requirement: &id001 !ruby/object:Gem::Requirement
26
- none: false
27
- requirements:
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
28
17
  - - ">="
29
- - !ruby/object:Gem::Version
30
- hash: 3
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
- requirement: &id002 !ruby/object:Gem::Requirement
40
- none: false
41
- requirements:
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
42
24
  - - ">="
43
- - !ruby/object:Gem::Version
44
- hash: 3
45
- segments:
46
- - 0
47
- version: "0"
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
- requirement: &id003 !ruby/object:Gem::Requirement
54
- none: false
55
- requirements:
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
56
38
  - - ">="
57
- - !ruby/object:Gem::Version
58
- hash: 3
59
- segments:
60
- - 0
61
- version: "0"
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
- requirement: &id004 !ruby/object:Gem::Requirement
68
- none: false
69
- requirements:
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
- hash: 3
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
- requirement: &id005 !ruby/object:Gem::Requirement
82
- none: false
83
- requirements:
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
84
66
  - - ">="
85
- - !ruby/object:Gem::Version
86
- hash: 3
87
- segments:
88
- - 0
89
- version: "0"
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
- requirement: &id006 !ruby/object:Gem::Requirement
96
- none: false
97
- requirements:
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
98
80
  - - ">="
99
- - !ruby/object:Gem::Version
100
- hash: 3
101
- segments:
102
- - 0
103
- version: "0"
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
- version_requirements: *id006
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
- files:
116
- - .gitignore
117
- - .rspec
118
- - .travis.yml
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
- none: false
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
- none: false
328
- requirements:
308
+ required_rubygems_version: !ruby/object:Gem::Requirement
309
+ requirements:
329
310
  - - ">="
330
- - !ruby/object:Gem::Version
331
- hash: 3
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: 1.5.3
315
+ rubygems_version: 2.5.0
339
316
  signing_key:
340
- specification_version: 3
341
- summary: Yt makes it easy to interact with Youtube V3 API by providing a modular, intuitive and tested Ruby-style API.
342
- test_files:
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: