yt 0.25.13 → 0.32.2

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.
Files changed (96) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +305 -1
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +86 -5
  5. data/YOUTUBE_IT.md +3 -3
  6. data/lib/yt.rb +5 -2
  7. data/lib/yt/actions/list.rb +3 -3
  8. data/lib/yt/associations/has_authentication.rb +33 -1
  9. data/lib/yt/associations/has_reports.rb +13 -18
  10. data/lib/yt/collections/assets.rb +2 -2
  11. data/lib/yt/collections/authentications.rb +9 -2
  12. data/lib/yt/collections/base.rb +3 -3
  13. data/lib/yt/collections/bulk_report_jobs.rb +28 -0
  14. data/lib/yt/collections/bulk_reports.rb +24 -0
  15. data/lib/yt/collections/claims.rb +22 -1
  16. data/lib/yt/collections/comment_threads.rb +41 -0
  17. data/lib/yt/collections/content_owners.rb +1 -1
  18. data/lib/yt/collections/group_infos.rb +27 -0
  19. data/lib/yt/collections/group_items.rb +45 -0
  20. data/lib/yt/collections/reports.rb +75 -13
  21. data/lib/yt/collections/revocations.rb +30 -0
  22. data/lib/yt/collections/video_groups.rb +29 -0
  23. data/lib/yt/collections/videos.rb +34 -9
  24. data/lib/yt/constants/geography.rb +326 -0
  25. data/lib/yt/errors/forbidden.rb +1 -3
  26. data/lib/yt/errors/no_items.rb +1 -3
  27. data/lib/yt/errors/request_error.rb +10 -7
  28. data/lib/yt/errors/server_error.rb +1 -3
  29. data/lib/yt/errors/unauthorized.rb +3 -3
  30. data/lib/yt/models/account.rb +12 -0
  31. data/lib/yt/models/advertising_options_set.rb +4 -4
  32. data/lib/yt/models/bulk_report.rb +23 -0
  33. data/lib/yt/models/bulk_report_job.rb +23 -0
  34. data/lib/yt/models/channel.rb +21 -12
  35. data/lib/yt/models/claim.rb +13 -2
  36. data/lib/yt/models/comment.rb +37 -0
  37. data/lib/yt/models/comment_thread.rb +50 -0
  38. data/lib/yt/models/content_detail.rb +6 -0
  39. data/lib/yt/models/content_owner.rb +31 -1
  40. data/lib/yt/models/group_info.rb +16 -0
  41. data/lib/yt/models/group_item.rb +15 -0
  42. data/lib/yt/models/resource.rb +3 -10
  43. data/lib/yt/models/revocation.rb +12 -0
  44. data/lib/yt/models/right_owner.rb +0 -2
  45. data/lib/yt/models/snippet.rb +24 -3
  46. data/lib/yt/models/video.rb +42 -11
  47. data/lib/yt/models/video_group.rb +186 -0
  48. data/lib/yt/request.rb +5 -3
  49. data/lib/yt/version.rb +2 -2
  50. data/spec/collections/comment_threads_spec.rb +46 -0
  51. data/spec/collections/playlist_items_spec.rb +1 -1
  52. data/spec/collections/reports_spec.rb +2 -2
  53. data/spec/constants/geography_spec.rb +16 -0
  54. data/spec/models/annotation_spec.rb +1 -1
  55. data/spec/models/claim_spec.rb +15 -3
  56. data/spec/models/comment_spec.rb +40 -0
  57. data/spec/models/comment_thread_spec.rb +93 -0
  58. data/spec/models/content_detail_spec.rb +7 -0
  59. data/spec/models/reference_spec.rb +2 -2
  60. data/spec/models/request_spec.rb +21 -0
  61. data/spec/models/resource_spec.rb +0 -15
  62. data/spec/models/video_spec.rb +1 -1
  63. data/spec/requests/as_account/account_spec.rb +16 -4
  64. data/spec/requests/as_account/authentications_spec.rb +1 -13
  65. data/spec/requests/as_account/channel_spec.rb +15 -45
  66. data/spec/requests/as_account/playlist_item_spec.rb +3 -3
  67. data/spec/requests/as_account/playlist_spec.rb +5 -32
  68. data/spec/requests/as_account/video_spec.rb +2022 -21
  69. data/spec/requests/as_content_owner/account_spec.rb +4 -0
  70. data/spec/requests/as_content_owner/bulk_report_job_spec.rb +19 -0
  71. data/spec/requests/as_content_owner/channel_spec.rb +59 -270
  72. data/spec/requests/as_content_owner/content_owner_spec.rb +89 -1
  73. data/spec/requests/as_content_owner/playlist_spec.rb +0 -15
  74. data/spec/requests/as_content_owner/video_group_spec.rb +112 -0
  75. data/spec/requests/as_content_owner/video_spec.rb +72 -146
  76. data/spec/requests/as_server_app/channel_spec.rb +1 -21
  77. data/spec/requests/as_server_app/comment_spec.rb +22 -0
  78. data/spec/requests/as_server_app/comment_thread_spec.rb +27 -0
  79. data/spec/requests/as_server_app/comment_threads_spec.rb +41 -0
  80. data/spec/requests/as_server_app/playlist_item_spec.rb +2 -2
  81. data/spec/requests/as_server_app/playlist_spec.rb +1 -22
  82. data/spec/requests/as_server_app/video_spec.rb +21 -19
  83. data/spec/requests/as_server_app/videos_spec.rb +5 -5
  84. data/spec/requests/unauthenticated/video_spec.rb +1 -9
  85. data/spec/spec_helper.rb +1 -1
  86. data/yt.gemspec +2 -1
  87. metadata +51 -17
  88. data/lib/yt/collections/ids.rb +0 -27
  89. data/lib/yt/config.rb +0 -54
  90. data/lib/yt/models/configuration.rb +0 -70
  91. data/lib/yt/models/description.rb +0 -58
  92. data/lib/yt/models/url.rb +0 -91
  93. data/spec/models/configuration_spec.rb +0 -44
  94. data/spec/models/description_spec.rb +0 -94
  95. data/spec/models/url_spec.rb +0 -84
  96. data/spec/requests/as_account/resource_spec.rb +0 -18
@@ -14,6 +14,71 @@ describe Yt::ContentOwner, :partner do
14
14
  end
15
15
  end
16
16
 
17
+ describe '.videos' do
18
+ let(:video) { $content_owner.videos.where(order: 'viewCount').first }
19
+
20
+ specify 'returns the videos in network with the content owner with their tags and category ID' do
21
+ expect(video).to be_a Yt::Video
22
+ expect(video.tags).not_to be_empty
23
+ expect(video.category_id).not_to be_nil
24
+ end
25
+
26
+ describe '.includes(:snippet)' do
27
+ let(:video) { $content_owner.videos.includes(:snippet).first }
28
+
29
+ specify 'eager-loads the *full* snippet of each video' do
30
+ expect(video.instance_variable_defined? :@snippet).to be true
31
+ expect(video.channel_title).to be
32
+ expect(video.snippet).to be_complete
33
+ end
34
+ end
35
+
36
+ describe '.includes(:statistics, :status)' do
37
+ let(:video) { $content_owner.videos.includes(:statistics, :status).first }
38
+
39
+ specify 'eager-loads the statistics and status of each video' do
40
+ expect(video.instance_variable_defined? :@statistics_set).to be true
41
+ expect(video.instance_variable_defined? :@status).to be true
42
+ end
43
+ end
44
+
45
+ describe '.includes(:content_details)' do
46
+ let(:video) { $content_owner.videos.includes(:content_details).first }
47
+
48
+ specify 'eager-loads the statistics of each video' do
49
+ expect(video.instance_variable_defined? :@content_detail).to be true
50
+ end
51
+ end
52
+
53
+ describe '.includes(:claim)' do
54
+ let(:videos) { $content_owner.videos.includes(:claim) }
55
+ let(:video_with_claim) { videos.find{|v| v.claim.present?} }
56
+
57
+ specify 'eager-loads the claim of each video and its asset' do
58
+ expect(video_with_claim.claim).to be_a Yt::Claim
59
+ expect(video_with_claim.claim.id).to be_a String
60
+ expect(video_with_claim.claim.video_id).to eq video_with_claim.id
61
+ expect(video_with_claim.claim.asset).to be_a Yt::Asset
62
+ expect(video_with_claim.claim.asset.id).to be_a String
63
+ end
64
+ end
65
+ end
66
+
67
+ describe '.video_groups' do
68
+ let(:video_group) { $content_owner.video_groups.first }
69
+
70
+ specify 'returns the first video-group created by the account' do
71
+ expect(video_group).to be_a Yt::VideoGroup
72
+ expect(video_group.title).to be_a String
73
+ expect(video_group.item_count).to be_an Integer
74
+ expect(video_group.published_at).to be_a Time
75
+ end
76
+
77
+ specify 'allows to run reports against each video-group' do
78
+ expect(video_group.views).to be
79
+ end
80
+ end
81
+
17
82
  describe 'claims' do
18
83
  let(:asset_id) { ENV['YT_TEST_PARTNER_ASSET_ID'] }
19
84
  let(:video_id) { ENV['YT_TEST_PARTNER_CLAIMABLE_VIDEO_ID'] }
@@ -227,6 +292,29 @@ describe Yt::ContentOwner, :partner do
227
292
  end
228
293
  end
229
294
 
295
+ describe '.assets' do
296
+ describe 'given the content owner has assets' do
297
+ let(:asset) { $content_owner.assets.first }
298
+
299
+ it 'returns valid asset' do
300
+ expect(asset.id).to be_a String
301
+ expect(asset.type).to be_a String
302
+ expect(asset.title).to be_a String
303
+ expect(asset.custom_id).to be_a String
304
+ end
305
+ end
306
+ end
307
+
308
+ describe '.bulk_report_jobs' do
309
+ describe 'given the content owner has bulk report jobs' do
310
+ let(:job) { $content_owner.bulk_report_jobs.first }
311
+
312
+ it 'returns valid job' do
313
+ expect(job.id).to be_a String
314
+ expect(job.report_type_id).to be_a String
315
+ end
316
+ end
317
+ end
230
318
  # @note: The following test works, but YouTube API endpoint to mark
231
319
  # an asset as 'invalid' (soft-delete) does not work, and apparently
232
320
  # there is no way to update the status of a asset.
@@ -238,4 +326,4 @@ describe Yt::ContentOwner, :partner do
238
326
  # after { @asset.delete } # This does not seem to work
239
327
  # it { expect(@asset).to be_a Yt::Asset }
240
328
  # end
241
- end
329
+ end
@@ -100,21 +100,6 @@ describe Yt::Playlist, :partner do
100
100
  end
101
101
  end
102
102
 
103
- describe "#{metric} can be retrieved for a specific day" do
104
- let(:metric) { metric }
105
- let(:result) { playlist.public_send "#{metric}_on", date }
106
-
107
- context 'in which the playlist had data' do
108
- let(:date) { ENV['YT_TEST_PARTNER_VIDEO_DATE'] }
109
- it { expect(result).to be_a type }
110
- end
111
-
112
- context 'in the future' do
113
- let(:date) { 5.days.from_now }
114
- it { expect(result).to be_nil }
115
- end
116
- end
117
-
118
103
  describe "#{metric} can be grouped by range" do
119
104
  let(:metric) { metric }
120
105
 
@@ -0,0 +1,112 @@
1
+ require 'spec_helper'
2
+ require 'yt/models/video_group'
3
+ require 'yt/models/group_item'
4
+
5
+ describe Yt::VideoGroup, :partner do
6
+ subject(:video_group) { Yt::VideoGroup.new id: id, auth: $content_owner }
7
+
8
+ context 'given a channel-group', :partner do
9
+ context 'managed by the authenticated Content Owner' do
10
+ let(:id) { ENV['YT_TEST_PARTNER_CHANNEL_GROUP_ID'] }
11
+
12
+ specify '.videos loads each video of each channel' do
13
+ video = video_group.videos.first
14
+ expect(video.instance_variable_defined? :@snippet).to be true
15
+ expect(video.instance_variable_defined? :@status).to be true
16
+ expect(video.instance_variable_defined? :@statistics_set).to be true
17
+ end
18
+
19
+ specify '.channels loads each channel' do
20
+ channel = video_group.channels.first
21
+ expect(channel.instance_variable_defined? :@snippet).to be true
22
+ end
23
+ end
24
+ end
25
+
26
+ context 'given a video-group', :partner do
27
+ context 'managed by the authenticated Content Owner' do
28
+ let(:id) { ENV['YT_TEST_PARTNER_VIDEO_GROUP_ID'] }
29
+
30
+ specify 'the title can be retrieved' do
31
+ expect(video_group.title).to be_a(String)
32
+ expect(video_group.title).not_to be_empty
33
+ end
34
+
35
+ specify 'the number of videos in the group can be retrieved' do
36
+ expect(video_group.item_count).to be_an(Integer)
37
+ expect(video_group.item_count).not_to be_zero
38
+ end
39
+
40
+ specify '.group_items retrieves the group items' do
41
+ expect(video_group.group_items.count).to be_an(Integer)
42
+ expect(video_group.group_items.map{|g| g}).to all(be_a Yt::GroupItem)
43
+ end
44
+
45
+ specify '.group_items.includes(:video) eager-loads each video' do
46
+ item = video_group.group_items.includes(:video).first
47
+ expect(item.video.instance_variable_defined? :@snippet).to be true
48
+ expect(item.video.instance_variable_defined? :@status).to be true
49
+ expect(item.video.instance_variable_defined? :@statistics_set).to be true
50
+ end
51
+
52
+ specify '.videos loads each video' do
53
+ video = video_group.videos.first
54
+ expect(video.instance_variable_defined? :@snippet).to be true
55
+ expect(video.instance_variable_defined? :@status).to be true
56
+ expect(video.instance_variable_defined? :@statistics_set).to be true
57
+ end
58
+
59
+ specify '.channels loads each channel' do
60
+ channel = video_group.channels.first
61
+ expect(channel.instance_variable_defined? :@snippet).to be true
62
+ end
63
+
64
+ describe 'multiple reports can be retrieved at once' do
65
+ metrics = {views: Integer,
66
+ estimated_minutes_watched: Integer, comments: Integer, likes: Integer,
67
+ dislikes: Integer, shares: Integer, subscribers_gained: Integer,
68
+ subscribers_lost: Integer,
69
+ videos_added_to_playlists: Integer, videos_removed_from_playlists: Integer,
70
+ average_view_duration: Integer,
71
+ card_impressions: Integer, card_clicks: Integer,
72
+ card_click_rate: Float, card_teaser_impressions: Integer,
73
+ card_teaser_clicks: Integer, card_teaser_click_rate: Float,
74
+ average_view_percentage: Float, annotation_clicks: Integer,
75
+ annotation_click_through_rate: Float,
76
+ annotation_close_rate: Float, estimated_revenue: Float, ad_impressions: Integer,
77
+ monetized_playbacks: Integer}
78
+
79
+ specify 'by day, and are chronologically sorted' do
80
+ range = {since: 5.days.ago.to_date, until: 3.days.ago.to_date}
81
+ result = video_group.reports range.merge(only: metrics, by: :day)
82
+ metrics.each do |metric, type|
83
+ expect(result[metric].keys).to all(be_a Date)
84
+ expect(result[metric].values).to all(be_a type)
85
+ expect(result[metric].keys.sort).to eq result[metric].keys
86
+ end
87
+ end
88
+
89
+ # NOTE: all the other filters also apply, not tested for brevity
90
+ end
91
+
92
+ describe 'viewer_percentage can be grouped by age group' do
93
+ let(:range) { {since: 1.year.ago.to_date, until: 1.week.ago.to_date} }
94
+ let(:keys) { range.values }
95
+
96
+ specify 'with the :by option set to :age_group' do
97
+ viewer_percentage = video_group.viewer_percentage range.merge by: :age_group
98
+ expect(viewer_percentage.keys - %w(65- 35-44 45-54 13-17 25-34 55-64 18-24)).to be_empty
99
+ expect(viewer_percentage.values).to all(be_instance_of Float)
100
+ end
101
+ end
102
+ end
103
+
104
+ context 'not managed by the authenticated Content Owner' do
105
+ let(:id) { 'ABExJp9gAAA' }
106
+
107
+ specify 'views cannot be retrieved' do
108
+ expect{video_group.views}.to raise_error Yt::Error
109
+ end
110
+ end
111
+ end
112
+ end
@@ -13,13 +13,15 @@ describe Yt::Video, :partner do
13
13
  it { expect{video.advertising_options_set}.not_to raise_error }
14
14
  end
15
15
 
16
- [:views, :uniques, :comments, :likes, :dislikes, :shares,
17
- :subscribers_gained, :subscribers_lost, :favorites_added,
16
+ [:views, :comments, :likes, :dislikes, :shares,
17
+ :subscribers_gained, :subscribers_lost,
18
18
  :videos_added_to_playlists, :videos_removed_from_playlists,
19
- :favorites_removed, :estimated_minutes_watched, :average_view_duration,
20
- :average_view_percentage, :impressions, :monetized_playbacks,
19
+ :estimated_minutes_watched, :average_view_duration,
20
+ :average_view_percentage, :ad_impressions, :monetized_playbacks,
21
21
  :annotation_clicks, :annotation_click_through_rate, :playback_based_cpm,
22
- :annotation_close_rate, :earnings].each do |metric|
22
+ :card_impressions, :card_clicks, :card_click_rate,
23
+ :card_teaser_impressions, :card_teaser_clicks, :card_teaser_click_rate,
24
+ :annotation_close_rate, :estimated_revenue].each do |metric|
23
25
  describe "#{metric} can be retrieved for a range of days" do
24
26
  let(:date_in) { ENV['YT_TEST_PARTNER_VIDEO_DATE'] }
25
27
  let(:date_out) { Date.parse(ENV['YT_TEST_PARTNER_VIDEO_DATE']) + 5 }
@@ -88,60 +90,18 @@ describe Yt::Video, :partner do
88
90
  end
89
91
  end
90
92
 
91
- {views: Integer, comments: Integer, dislikes: Integer,
92
- estimated_minutes_watched: Integer, average_view_duration: Integer,
93
- average_view_percentage: Float, impressions: Integer,
94
- subscribers_lost: Integer, subscribers_gained: Integer, likes: Integer,
95
- monetized_playbacks: Integer, earnings: Float}.each do |metric, type|
96
- describe "#{metric} can be retrieved for a specific day" do
97
- let(:metric) { metric }
98
- let(:result) { video.public_send "#{metric}_on", date }
99
-
100
- context 'in which the video had data' do
101
- let(:date) { ENV['YT_TEST_PARTNER_VIDEO_DATE'] }
102
- it { expect(result).to be_a type }
103
- end
104
-
105
- context 'in the future' do
106
- let(:date) { 5.days.from_now }
107
- it { expect(result).to be_nil }
108
- end
109
- end
110
- end
111
-
112
93
  {views: Integer, comments: Integer, likes: Integer, dislikes: Integer,
113
94
  shares: Integer, subscribers_gained: Integer, subscribers_lost: Integer,
114
- favorites_added: Integer,
115
95
  videos_added_to_playlists: Integer, videos_removed_from_playlists: Integer,
116
96
  estimated_minutes_watched: Integer, average_view_duration: Integer,
117
- average_view_percentage: Float, impressions: Integer,
97
+ average_view_percentage: Float, ad_impressions: Integer,
118
98
  monetized_playbacks: Integer, annotation_clicks: Integer,
119
99
  annotation_click_through_rate: Float, annotation_close_rate: Float,
120
- earnings: Float}.each do |metric, type|
121
- describe "#{metric} can be grouped by range" do
122
- let(:metric) { metric }
123
-
124
- context 'without a :by option (default)' do
125
- let(:result) { video.public_send metric }
126
- specify do
127
- expect(result.size).to be 1
128
- expect(result[:total]).to be_a type
129
- end
130
- end
131
-
132
- context 'with the :by option set to :range' do
133
- let(:result) { video.public_send metric, by: :range }
134
- specify do
135
- expect(result.size).to be 1
136
- expect(result[:total]).to be_a type
137
- end
138
- end
139
- end
140
- end
141
-
142
- {favorites_removed: Integer}.each do |metric, type|
100
+ card_impressions: Integer, card_clicks: Integer,
101
+ card_click_rate: Float, card_teaser_impressions: Integer,
102
+ card_teaser_clicks: Integer, card_teaser_click_rate: Float,
103
+ estimated_revenue: Float}.each do |metric, type|
143
104
  describe "#{metric} can be grouped by range" do
144
- let(:id) { 'NeMlqbX2Ifg' }
145
105
  let(:metric) { metric }
146
106
 
147
107
  context 'without a :by option (default)' do
@@ -163,12 +123,14 @@ describe Yt::Video, :partner do
163
123
  end
164
124
 
165
125
  [:views, :comments, :likes, :dislikes, :shares,
166
- :subscribers_gained, :subscribers_lost, :favorites_added,
126
+ :subscribers_gained, :subscribers_lost,
167
127
  :videos_added_to_playlists, :videos_removed_from_playlists,
168
128
  :estimated_minutes_watched, :average_view_duration,
169
- :average_view_percentage, :impressions, :monetized_playbacks,
129
+ :average_view_percentage, :ad_impressions, :monetized_playbacks,
130
+ :card_impressions, :card_clicks, :card_click_rate,
131
+ :card_teaser_impressions, :card_teaser_clicks, :card_teaser_click_rate,
170
132
  :annotation_clicks, :annotation_click_through_rate,
171
- :annotation_close_rate, :earnings].each do |metric|
133
+ :annotation_close_rate, :estimated_revenue].each do |metric|
172
134
  describe "#{metric} can be retrieved for a single country" do
173
135
  let(:result) { video.public_send metric, options }
174
136
 
@@ -189,6 +151,8 @@ describe Yt::Video, :partner do
189
151
  end
190
152
 
191
153
  [:views, :annotation_clicks, :annotation_click_through_rate,
154
+ :card_impressions, :card_clicks, :card_click_rate,
155
+ :card_teaser_impressions, :card_teaser_clicks, :card_teaser_click_rate,
192
156
  :annotation_close_rate].each do |metric|
193
157
  describe "#{metric} can be retrieved for a single country" do
194
158
  let(:result) { video.public_send metric, options }
@@ -210,15 +174,18 @@ describe Yt::Video, :partner do
210
174
  end
211
175
 
212
176
  describe 'multiple reports can be retrieved at once' do
213
- metrics = {views: Integer, uniques: Integer,
177
+ metrics = {views: Integer,
214
178
  estimated_minutes_watched: Integer, comments: Integer, likes: Integer,
215
179
  dislikes: Integer, shares: Integer, subscribers_gained: Integer,
216
- subscribers_lost: Integer, favorites_added: Integer,
180
+ subscribers_lost: Integer,
217
181
  videos_added_to_playlists: Integer, videos_removed_from_playlists: Integer,
218
- favorites_removed: Integer, average_view_duration: Integer,
182
+ average_view_duration: Integer,
219
183
  average_view_percentage: Float, annotation_clicks: Integer,
184
+ card_impressions: Integer, card_clicks: Integer,
185
+ card_click_rate: Float, card_teaser_impressions: Integer,
186
+ card_teaser_clicks: Integer, card_teaser_click_rate: Float,
220
187
  annotation_click_through_rate: Float,
221
- annotation_close_rate: Float, earnings: Float, impressions: Integer,
188
+ annotation_close_rate: Float, estimated_revenue: Float, ad_impressions: Integer,
222
189
  monetized_playbacks: Integer}
223
190
 
224
191
  specify 'by day' do
@@ -255,24 +222,24 @@ describe Yt::Video, :partner do
255
222
  end
256
223
  end
257
224
 
258
- describe 'earnings can be grouped by day' do
225
+ describe 'estimated_revenue can be grouped by day' do
259
226
  let(:range) { {since: 4.days.ago.to_date, until: 3.days.ago.to_date} }
260
227
  let(:keys) { range.values }
261
228
 
262
229
  specify 'with the :by option set to :day' do
263
- earnings = video.earnings range.merge by: :day
264
- expect(earnings.keys).to eq range.values
230
+ estimated_revenue = video.estimated_revenue range.merge by: :day
231
+ expect(estimated_revenue.keys).to eq range.values
265
232
  end
266
233
  end
267
234
 
268
- describe 'earnings can be grouped by country' do
235
+ describe 'estimated_revenue can be grouped by country' do
269
236
  let(:range) { {since: 4.days.ago, until: 3.days.ago} }
270
237
 
271
238
  specify 'with the :by option set to :country' do
272
- earnings = video.earnings range.merge by: :country
273
- expect(earnings.keys).to all(be_a String)
274
- expect(earnings.keys.map(&:length).uniq).to eq [2]
275
- expect(earnings.values).to all(be_a Float)
239
+ estimated_revenue = video.estimated_revenue range.merge by: :country
240
+ expect(estimated_revenue.keys).to all(be_a String)
241
+ expect(estimated_revenue.keys.map(&:length).uniq).to eq [2]
242
+ expect(estimated_revenue.values).to all(be_a Float)
276
243
  end
277
244
  end
278
245
 
@@ -383,10 +350,31 @@ describe Yt::Video, :partner do
383
350
 
384
351
  describe 'views can be grouped by device type' do
385
352
  let(:range) { {since: ENV['YT_TEST_PARTNER_VIDEO_DATE']} }
353
+ let(:keys) { Yt::Collections::Reports::DEVICE_TYPES.keys }
386
354
 
387
355
  specify 'with the :by option set to :device_type' do
388
356
  views = video.views range.merge by: :device_type
389
- expect(views.keys).to all(be_instance_of Symbol)
357
+ expect(views.keys - keys).to be_empty
358
+ expect(views.values).to all(be_an Integer)
359
+ end
360
+ end
361
+
362
+ describe 'views can be grouped by operating system' do
363
+ let(:keys) { Yt::Collections::Reports::OPERATING_SYSTEMS.keys }
364
+
365
+ specify 'with the :by option set to :operating_system' do
366
+ views = video.views by: :operating_system
367
+ expect(views.keys - keys).to be_empty
368
+ expect(views.values).to all(be_an Integer)
369
+ end
370
+ end
371
+
372
+ describe 'views can be grouped by YouTube product' do
373
+ let(:keys) { Yt::Collections::Reports::YOUTUBE_PRODUCTS.keys }
374
+
375
+ specify 'with the :by option set to :youtube_product' do
376
+ views = video.views by: :youtube_product
377
+ expect(views.keys - keys).to be_empty
390
378
  expect(views.values).to all(be_an Integer)
391
379
  end
392
380
  end
@@ -423,33 +411,14 @@ describe Yt::Video, :partner do
423
411
  end
424
412
  end
425
413
 
426
- describe 'uniques can be retrieved for a single US state' do
427
- let(:state_code) { 'NY' }
428
- let(:result) { video.uniques since: date, by: by, in: location }
429
- let(:date) { 4.days.ago }
430
-
431
- context 'and grouped by day' do
432
- let(:by) { :day }
433
-
434
- context 'with the :in option set to {state: state code}' do
435
- let(:location) { {state: state_code} }
436
- it { expect(result.keys.min).to eq date.to_date }
437
- end
438
-
439
- context 'with the :in option set to {country: "US", state: state code}' do
440
- let(:location) { {country: 'US', state: state_code} }
441
- it { expect(result.keys.min).to eq date.to_date }
442
- end
443
- end
444
- end
445
-
446
- describe 'uniques can be grouped by day' do
447
- let(:range) { {since: 4.days.ago.to_date, until: 3.days.ago.to_date} }
448
- let(:keys) { range.values }
414
+ describe 'views can be grouped by subscribed statuses' do
415
+ let(:range) { {since: ENV['YT_TEST_PARTNER_VIDEO_DATE']} }
416
+ let(:keys) { Yt::Collections::Reports::SUBSCRIBED_STATUSES.keys }
449
417
 
450
- specify 'with the :by option set to :day' do
451
- uniques = video.uniques range.merge by: :day
452
- expect(uniques.keys).to eq range.values
418
+ specify 'with the :by option set to subscribed statuses' do
419
+ views = video.views range.merge by: :subscribed_status
420
+ expect(views.keys - keys).to be_empty
421
+ expect(views.values).to all(be_an Integer)
453
422
  end
454
423
  end
455
424
 
@@ -621,49 +590,6 @@ describe Yt::Video, :partner do
621
590
  end
622
591
  end
623
592
 
624
- describe 'added favorites can be grouped by day' do
625
- let(:range) { {since: 4.days.ago.to_date, until: 3.days.ago.to_date} }
626
- let(:keys) { range.values }
627
-
628
- specify 'with the :by option set to :day' do
629
- favorites_added = video.favorites_added range.merge by: :day
630
- expect(favorites_added.keys).to eq range.values
631
- end
632
- end
633
-
634
- describe 'added favorites can be grouped by country' do
635
- let(:range) { {since: ENV['YT_TEST_PARTNER_VIDEO_DATE']} }
636
-
637
- specify 'with the :by option set to :country' do
638
- favorites_added = video.favorites_added range.merge by: :country
639
- expect(favorites_added.keys).to all(be_a String)
640
- expect(favorites_added.keys.map(&:length).uniq).to eq [2]
641
- expect(favorites_added.values).to all(be_an Integer)
642
- end
643
- end
644
-
645
- describe 'removed favorites can be grouped by day' do
646
- let(:range) { {since: 4.days.ago.to_date, until: 3.days.ago.to_date} }
647
- let(:keys) { range.values }
648
-
649
- specify 'with the :by option set to :day' do
650
- favorites_removed = video.favorites_removed range.merge by: :day
651
- expect(favorites_removed.keys).to eq range.values
652
- end
653
- end
654
-
655
- # TODO: Remove "removed favorites" since it’s deprecated!
656
- # describe 'removed favorites can be grouped by country' do
657
- # let(:range) { {since: ENV['YT_TEST_PARTNER_VIDEO_DATE']} }
658
- #
659
- # specify 'with the :by option set to :country' do
660
- # favorites_removed = video.favorites_removed range.merge by: :country
661
- # expect(favorites_removed.keys).to all(be_a String)
662
- # expect(favorites_removed.keys.map(&:length).uniq).to eq [2]
663
- # expect(favorites_removed.values).to all(be_an Integer)
664
- # end
665
- # end
666
-
667
593
  describe 'estimated minutes watched can be retrieved for a single US state' do
668
594
  let(:state_code) { 'NY' }
669
595
  let(:minutes) { video.estimated_minutes_watched since: date, by: by, in: location }
@@ -928,24 +854,24 @@ describe Yt::Video, :partner do
928
854
  end
929
855
  end
930
856
 
931
- describe 'impressions can be grouped by day' do
857
+ describe 'ad_impressions can be grouped by day' do
932
858
  let(:range) { {since: 4.days.ago.to_date, until: 3.days.ago.to_date} }
933
859
  let(:keys) { range.values }
934
860
 
935
861
  specify 'with the :by option set to :day' do
936
- impressions = video.impressions range.merge by: :day
937
- expect(impressions.keys).to eq range.values
862
+ ad_impressions = video.ad_impressions range.merge by: :day
863
+ expect(ad_impressions.keys).to eq range.values
938
864
  end
939
865
  end
940
866
 
941
- describe 'impressions can be grouped by country' do
867
+ describe 'ad_impressions can be grouped by country' do
942
868
  let(:range) { {since: ENV['YT_TEST_PARTNER_VIDEO_DATE']} }
943
869
 
944
870
  specify 'with the :by option set to :country' do
945
- impressions = video.impressions range.merge by: :country
946
- expect(impressions.keys).to all(be_a String)
947
- expect(impressions.keys.map(&:length).uniq).to eq [2]
948
- expect(impressions.values).to all(be_an Integer)
871
+ ad_impressions = video.ad_impressions range.merge by: :country
872
+ expect(ad_impressions.keys).to all(be_a String)
873
+ expect(ad_impressions.keys.map(&:length).uniq).to eq [2]
874
+ expect(ad_impressions.values).to all(be_an Integer)
949
875
  end
950
876
  end
951
877
 
@@ -1282,4 +1208,4 @@ describe Yt::Video, :partner do
1282
1208
  end
1283
1209
  end
1284
1210
  end
1285
- end
1211
+ end