yt 0.25.13 → 0.32.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +305 -1
- data/MIT-LICENSE +1 -1
- data/README.md +86 -5
- data/YOUTUBE_IT.md +3 -3
- data/lib/yt.rb +5 -2
- data/lib/yt/actions/list.rb +3 -3
- data/lib/yt/associations/has_authentication.rb +33 -1
- data/lib/yt/associations/has_reports.rb +13 -18
- data/lib/yt/collections/assets.rb +2 -2
- data/lib/yt/collections/authentications.rb +9 -2
- data/lib/yt/collections/base.rb +3 -3
- data/lib/yt/collections/bulk_report_jobs.rb +28 -0
- data/lib/yt/collections/bulk_reports.rb +24 -0
- data/lib/yt/collections/claims.rb +22 -1
- data/lib/yt/collections/comment_threads.rb +41 -0
- data/lib/yt/collections/content_owners.rb +1 -1
- data/lib/yt/collections/group_infos.rb +27 -0
- data/lib/yt/collections/group_items.rb +45 -0
- data/lib/yt/collections/reports.rb +75 -13
- data/lib/yt/collections/revocations.rb +30 -0
- data/lib/yt/collections/video_groups.rb +29 -0
- data/lib/yt/collections/videos.rb +34 -9
- data/lib/yt/constants/geography.rb +326 -0
- data/lib/yt/errors/forbidden.rb +1 -3
- data/lib/yt/errors/no_items.rb +1 -3
- data/lib/yt/errors/request_error.rb +10 -7
- data/lib/yt/errors/server_error.rb +1 -3
- data/lib/yt/errors/unauthorized.rb +3 -3
- data/lib/yt/models/account.rb +12 -0
- data/lib/yt/models/advertising_options_set.rb +4 -4
- data/lib/yt/models/bulk_report.rb +23 -0
- data/lib/yt/models/bulk_report_job.rb +23 -0
- data/lib/yt/models/channel.rb +21 -12
- data/lib/yt/models/claim.rb +13 -2
- data/lib/yt/models/comment.rb +37 -0
- data/lib/yt/models/comment_thread.rb +50 -0
- data/lib/yt/models/content_detail.rb +6 -0
- data/lib/yt/models/content_owner.rb +31 -1
- data/lib/yt/models/group_info.rb +16 -0
- data/lib/yt/models/group_item.rb +15 -0
- data/lib/yt/models/resource.rb +3 -10
- data/lib/yt/models/revocation.rb +12 -0
- data/lib/yt/models/right_owner.rb +0 -2
- data/lib/yt/models/snippet.rb +24 -3
- data/lib/yt/models/video.rb +42 -11
- data/lib/yt/models/video_group.rb +186 -0
- data/lib/yt/request.rb +5 -3
- data/lib/yt/version.rb +2 -2
- data/spec/collections/comment_threads_spec.rb +46 -0
- data/spec/collections/playlist_items_spec.rb +1 -1
- data/spec/collections/reports_spec.rb +2 -2
- data/spec/constants/geography_spec.rb +16 -0
- data/spec/models/annotation_spec.rb +1 -1
- data/spec/models/claim_spec.rb +15 -3
- data/spec/models/comment_spec.rb +40 -0
- data/spec/models/comment_thread_spec.rb +93 -0
- data/spec/models/content_detail_spec.rb +7 -0
- data/spec/models/reference_spec.rb +2 -2
- data/spec/models/request_spec.rb +21 -0
- data/spec/models/resource_spec.rb +0 -15
- data/spec/models/video_spec.rb +1 -1
- data/spec/requests/as_account/account_spec.rb +16 -4
- data/spec/requests/as_account/authentications_spec.rb +1 -13
- data/spec/requests/as_account/channel_spec.rb +15 -45
- data/spec/requests/as_account/playlist_item_spec.rb +3 -3
- data/spec/requests/as_account/playlist_spec.rb +5 -32
- data/spec/requests/as_account/video_spec.rb +2022 -21
- data/spec/requests/as_content_owner/account_spec.rb +4 -0
- data/spec/requests/as_content_owner/bulk_report_job_spec.rb +19 -0
- data/spec/requests/as_content_owner/channel_spec.rb +59 -270
- data/spec/requests/as_content_owner/content_owner_spec.rb +89 -1
- data/spec/requests/as_content_owner/playlist_spec.rb +0 -15
- data/spec/requests/as_content_owner/video_group_spec.rb +112 -0
- data/spec/requests/as_content_owner/video_spec.rb +72 -146
- data/spec/requests/as_server_app/channel_spec.rb +1 -21
- data/spec/requests/as_server_app/comment_spec.rb +22 -0
- data/spec/requests/as_server_app/comment_thread_spec.rb +27 -0
- data/spec/requests/as_server_app/comment_threads_spec.rb +41 -0
- data/spec/requests/as_server_app/playlist_item_spec.rb +2 -2
- data/spec/requests/as_server_app/playlist_spec.rb +1 -22
- data/spec/requests/as_server_app/video_spec.rb +21 -19
- data/spec/requests/as_server_app/videos_spec.rb +5 -5
- data/spec/requests/unauthenticated/video_spec.rb +1 -9
- data/spec/spec_helper.rb +1 -1
- data/yt.gemspec +2 -1
- metadata +51 -17
- data/lib/yt/collections/ids.rb +0 -27
- data/lib/yt/config.rb +0 -54
- data/lib/yt/models/configuration.rb +0 -70
- data/lib/yt/models/description.rb +0 -58
- data/lib/yt/models/url.rb +0 -91
- data/spec/models/configuration_spec.rb +0 -44
- data/spec/models/description_spec.rb +0 -94
- data/spec/models/url_spec.rb +0 -84
- 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, :
|
17
|
-
:subscribers_gained, :subscribers_lost,
|
16
|
+
[:views, :comments, :likes, :dislikes, :shares,
|
17
|
+
:subscribers_gained, :subscribers_lost,
|
18
18
|
:videos_added_to_playlists, :videos_removed_from_playlists,
|
19
|
-
:
|
20
|
-
:average_view_percentage, :
|
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
|
-
:
|
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,
|
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
|
-
|
121
|
-
|
122
|
-
|
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,
|
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, :
|
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, :
|
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,
|
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,
|
180
|
+
subscribers_lost: Integer,
|
217
181
|
videos_added_to_playlists: Integer, videos_removed_from_playlists: Integer,
|
218
|
-
|
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,
|
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 '
|
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
|
-
|
264
|
-
expect(
|
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 '
|
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
|
-
|
273
|
-
expect(
|
274
|
-
expect(
|
275
|
-
expect(
|
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
|
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 '
|
427
|
-
let(:
|
428
|
-
let(:
|
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
|
451
|
-
|
452
|
-
expect(
|
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 '
|
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
|
-
|
937
|
-
expect(
|
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 '
|
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
|
-
|
946
|
-
expect(
|
947
|
-
expect(
|
948
|
-
expect(
|
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
|