yt 0.32.6 → 0.33.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -4
- data/CHANGELOG.md +19 -0
- data/README.md +22 -32
- data/YOUTUBE_IT.md +4 -4
- data/lib/yt.rb +0 -1
- data/lib/yt/associations/has_reports.rb +9 -14
- data/lib/yt/collections/reports.rb +5 -7
- data/lib/yt/models/resource.rb +69 -3
- data/lib/yt/models/url.rb +2 -60
- data/lib/yt/request.rb +6 -2
- data/lib/yt/version.rb +1 -1
- data/yt.gemspec +5 -2
- metadata +31 -169
- data/spec/collections/claims_spec.rb +0 -62
- data/spec/collections/comment_threads_spec.rb +0 -46
- data/spec/collections/playlist_items_spec.rb +0 -44
- data/spec/collections/playlists_spec.rb +0 -27
- data/spec/collections/policies_spec.rb +0 -30
- data/spec/collections/references_spec.rb +0 -30
- data/spec/collections/reports_spec.rb +0 -30
- data/spec/collections/subscriptions_spec.rb +0 -25
- data/spec/collections/videos_spec.rb +0 -43
- data/spec/constants/geography_spec.rb +0 -16
- data/spec/errors/forbidden_spec.rb +0 -10
- data/spec/errors/missing_auth_spec.rb +0 -24
- data/spec/errors/no_items_spec.rb +0 -10
- data/spec/errors/request_error_spec.rb +0 -44
- data/spec/errors/server_error_spec.rb +0 -10
- data/spec/errors/unauthorized_spec.rb +0 -10
- data/spec/models/account_spec.rb +0 -138
- data/spec/models/annotation_spec.rb +0 -180
- data/spec/models/asset_spec.rb +0 -32
- data/spec/models/channel_spec.rb +0 -127
- data/spec/models/claim_event_spec.rb +0 -62
- data/spec/models/claim_history_spec.rb +0 -27
- data/spec/models/claim_spec.rb +0 -223
- data/spec/models/comment_spec.rb +0 -40
- data/spec/models/comment_thread_spec.rb +0 -93
- data/spec/models/configuration_spec.rb +0 -44
- data/spec/models/content_detail_spec.rb +0 -52
- data/spec/models/content_owner_detail_spec.rb +0 -6
- data/spec/models/file_detail_spec.rb +0 -13
- data/spec/models/live_streaming_detail_spec.rb +0 -6
- data/spec/models/ownership_spec.rb +0 -59
- data/spec/models/player_spec.rb +0 -13
- data/spec/models/playlist_item_spec.rb +0 -120
- data/spec/models/playlist_spec.rb +0 -138
- data/spec/models/policy_rule_spec.rb +0 -63
- data/spec/models/policy_spec.rb +0 -41
- data/spec/models/rating_spec.rb +0 -12
- data/spec/models/reference_spec.rb +0 -249
- data/spec/models/request_spec.rb +0 -204
- data/spec/models/resource_spec.rb +0 -42
- data/spec/models/right_owner_spec.rb +0 -71
- data/spec/models/snippet_spec.rb +0 -13
- data/spec/models/statistics_set_spec.rb +0 -13
- data/spec/models/status_spec.rb +0 -13
- data/spec/models/subscription_spec.rb +0 -30
- data/spec/models/url_spec.rb +0 -78
- data/spec/models/video_category_spec.rb +0 -21
- data/spec/models/video_spec.rb +0 -669
- data/spec/requests/as_account/account_spec.rb +0 -143
- data/spec/requests/as_account/authentications_spec.rb +0 -127
- data/spec/requests/as_account/channel_spec.rb +0 -246
- data/spec/requests/as_account/channels_spec.rb +0 -18
- data/spec/requests/as_account/playlist_item_spec.rb +0 -55
- data/spec/requests/as_account/playlist_spec.rb +0 -218
- data/spec/requests/as_account/thumbnail.jpg +0 -0
- data/spec/requests/as_account/video.mp4 +0 -0
- data/spec/requests/as_account/video_spec.rb +0 -408
- data/spec/requests/as_content_owner/account_spec.rb +0 -29
- data/spec/requests/as_content_owner/advertising_options_set_spec.rb +0 -15
- data/spec/requests/as_content_owner/asset_spec.rb +0 -31
- data/spec/requests/as_content_owner/bulk_report_job_spec.rb +0 -19
- data/spec/requests/as_content_owner/channel_spec.rb +0 -1836
- data/spec/requests/as_content_owner/claim_history_spec.rb +0 -20
- data/spec/requests/as_content_owner/claim_spec.rb +0 -17
- data/spec/requests/as_content_owner/content_owner_spec.rb +0 -370
- data/spec/requests/as_content_owner/match_policy_spec.rb +0 -17
- data/spec/requests/as_content_owner/ownership_spec.rb +0 -25
- data/spec/requests/as_content_owner/playlist_spec.rb +0 -767
- data/spec/requests/as_content_owner/video_group_spec.rb +0 -112
- data/spec/requests/as_content_owner/video_spec.rb +0 -1223
- data/spec/requests/as_server_app/channel_spec.rb +0 -54
- data/spec/requests/as_server_app/comment_spec.rb +0 -22
- data/spec/requests/as_server_app/comment_thread_spec.rb +0 -27
- data/spec/requests/as_server_app/comment_threads_spec.rb +0 -41
- data/spec/requests/as_server_app/playlist_item_spec.rb +0 -30
- data/spec/requests/as_server_app/playlist_spec.rb +0 -33
- data/spec/requests/as_server_app/url_spec.rb +0 -94
- data/spec/requests/as_server_app/video_spec.rb +0 -60
- data/spec/requests/as_server_app/videos_spec.rb +0 -40
- data/spec/requests/unauthenticated/video_spec.rb +0 -14
- data/spec/spec_helper.rb +0 -20
- data/spec/support/fail_matcher.rb +0 -15
- data/spec/support/global_hooks.rb +0 -48
@@ -1,143 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
require 'spec_helper'
|
3
|
-
require 'yt/models/account'
|
4
|
-
|
5
|
-
describe Yt::Account, :device_app do
|
6
|
-
describe 'can create playlists', rate_limited: true do
|
7
|
-
let(:params) { {title: 'Test Yt playlist', privacy_status: 'unlisted'} }
|
8
|
-
before { @playlist = $account.create_playlist params }
|
9
|
-
it { expect(@playlist).to be_a Yt::Playlist }
|
10
|
-
after { @playlist.delete }
|
11
|
-
end
|
12
|
-
|
13
|
-
it { expect($account.channel).to be_a Yt::Channel }
|
14
|
-
it { expect($account.playlists.first).to be_a Yt::Playlist }
|
15
|
-
it { expect($account.subscribed_channels.first).to be_a Yt::Channel }
|
16
|
-
it { expect($account.user_info).to be_a Yt::UserInfo }
|
17
|
-
|
18
|
-
describe '.related_playlists' do
|
19
|
-
let(:related_playlists) { $account.related_playlists }
|
20
|
-
|
21
|
-
specify 'returns the list of associated playlist (Liked Videos, Uploads, ...)' do
|
22
|
-
expect(related_playlists.first).to be_a Yt::Playlist
|
23
|
-
end
|
24
|
-
|
25
|
-
specify 'includes public related playlists (such as Liked Videos)' do
|
26
|
-
uploads = related_playlists.select{|p| p.title.starts_with? 'Uploads'}
|
27
|
-
expect(uploads).not_to be_empty
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
describe '.videos' do
|
32
|
-
let(:video) { $account.videos.where(order: 'viewCount').first }
|
33
|
-
|
34
|
-
specify 'returns the videos uploaded by the account with their tags and category ID' do
|
35
|
-
expect(video).to be_a Yt::Video
|
36
|
-
expect(video.tags).not_to be_empty
|
37
|
-
expect(video.category_id).not_to be_nil
|
38
|
-
end
|
39
|
-
|
40
|
-
describe '.where(q: query_string)' do
|
41
|
-
let(:count) { $account.videos.where(q: query).count }
|
42
|
-
|
43
|
-
context 'given a query string that matches any video owned by the account' do
|
44
|
-
let(:query) { ENV['YT_TEST_MATCHING_QUERY_STRING'] }
|
45
|
-
it { expect(count).to be > 0 }
|
46
|
-
end
|
47
|
-
|
48
|
-
context 'given a query string that does not match any video owned by the account' do
|
49
|
-
let(:query) { '--not-a-matching-query-string--' }
|
50
|
-
it { expect(count).to be_zero }
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
describe 'ignores filters by ID (all the videos uploaded by the account are returned)' do
|
55
|
-
let(:other_video) { $account.videos.where(order: 'viewCount', id: 'invalid').first }
|
56
|
-
it { expect(other_video.id).to eq video.id }
|
57
|
-
end
|
58
|
-
|
59
|
-
describe 'ignores filters by chart (all the videos uploaded by the account are returned)' do
|
60
|
-
let(:other_video) { $account.videos.where(order: 'viewCount', chart: 'invalid').first }
|
61
|
-
it { expect(other_video.id).to eq video.id }
|
62
|
-
end
|
63
|
-
|
64
|
-
describe '.includes(:snippet)' do
|
65
|
-
let(:video) { $account.videos.includes(:snippet).first }
|
66
|
-
|
67
|
-
specify 'eager-loads the *full* snippet of each video' do
|
68
|
-
expect(video.instance_variable_defined? :@snippet).to be true
|
69
|
-
expect(video.channel_title).to be
|
70
|
-
expect(video.snippet).to be_complete
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
describe '.includes(:statistics, :status)' do
|
75
|
-
let(:video) { $account.videos.includes(:statistics, :status).first }
|
76
|
-
|
77
|
-
specify 'eager-loads the statistics and status of each video' do
|
78
|
-
expect(video.instance_variable_defined? :@statistics_set).to be true
|
79
|
-
expect(video.instance_variable_defined? :@status).to be true
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
describe '.includes(:content_details)' do
|
84
|
-
let(:video) { $account.videos.includes(:content_details).first }
|
85
|
-
|
86
|
-
specify 'eager-loads the statistics of each video' do
|
87
|
-
expect(video.instance_variable_defined? :@content_detail).to be true
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
describe '.video_groups' do
|
93
|
-
let(:video_group) { $account.video_groups.first }
|
94
|
-
|
95
|
-
specify 'returns the first video-group created by the account' do
|
96
|
-
expect(video_group).to be_a Yt::VideoGroup
|
97
|
-
expect(video_group.title).to be_a String
|
98
|
-
expect(video_group.item_count).to be_an Integer
|
99
|
-
expect(video_group.published_at).to be_a Time
|
100
|
-
end
|
101
|
-
|
102
|
-
specify 'allows to run reports against each video-group' do
|
103
|
-
expect(video_group.views).to be
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
describe '.upload_video' do
|
108
|
-
let(:video_params) { {title: 'Test Yt upload', privacy_status: 'private', category_id: 17} }
|
109
|
-
let(:video) { $account.upload_video path_or_url, video_params }
|
110
|
-
after { video.delete }
|
111
|
-
|
112
|
-
context 'given the path to a local video file' do
|
113
|
-
let(:path_or_url) { File.expand_path '../video.mp4', __FILE__ }
|
114
|
-
|
115
|
-
it { expect(video).to be_a Yt::Video }
|
116
|
-
end
|
117
|
-
|
118
|
-
context 'given the URL of a remote video file' do
|
119
|
-
let(:path_or_url) { 'https://bit.ly/yt_test' }
|
120
|
-
|
121
|
-
it { expect(video).to be_a Yt::Video }
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
describe '.subscribers' do
|
126
|
-
let(:subscriber) { $account.subscribers.first }
|
127
|
-
|
128
|
-
# It could be only me, but it returns an empty array for "items".
|
129
|
-
# Just in case, I currently have 2 subscribers.
|
130
|
-
# {
|
131
|
-
# "kind": "youtube#subscriptionListResponse",
|
132
|
-
# "etag": "...",
|
133
|
-
# "pageInfo": {
|
134
|
-
# "totalResults": 2,
|
135
|
-
# "resultsPerPage": 50
|
136
|
-
# },
|
137
|
-
# "items": []
|
138
|
-
# }
|
139
|
-
specify 'returns the channels who are subscribed to me' do
|
140
|
-
expect(subscriber).to be_nil
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
@@ -1,127 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'yt/models/account'
|
3
|
-
|
4
|
-
describe Yt::Account, :device_app do
|
5
|
-
subject(:account) { Yt::Account.new attrs }
|
6
|
-
|
7
|
-
describe '#refresh' do
|
8
|
-
context 'given a valid refresh token' do
|
9
|
-
let(:attrs) { {refresh_token: ENV['YT_TEST_DEVICE_REFRESH_TOKEN']} }
|
10
|
-
|
11
|
-
# NOTE: When the token is refreshed, YouTube *might* actually return
|
12
|
-
# the *same* access token if it is still valid. Typically, within the
|
13
|
-
# same second, refreshing the token returns the same token. Still,
|
14
|
-
# testing that *expires_at* changes is a guarantee that we attempted
|
15
|
-
# to get a new token, which is what refresh is meant to do.
|
16
|
-
it { expect{account.refreshed_access_token?}.to change{account.expires_at} }
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
describe '#authentication' do
|
21
|
-
context 'given a refresh token' do
|
22
|
-
let(:attrs) { {refresh_token: refresh_token} }
|
23
|
-
|
24
|
-
context 'that is valid' do
|
25
|
-
let(:refresh_token) { ENV['YT_TEST_DEVICE_REFRESH_TOKEN'] }
|
26
|
-
it { expect(account.authentication).to be_a Yt::Authentication }
|
27
|
-
it { expect(account.refresh_token).to eq refresh_token }
|
28
|
-
end
|
29
|
-
|
30
|
-
context 'that is invalid' do
|
31
|
-
let(:refresh_token) { '--not-a-valid-refresh-token--' }
|
32
|
-
it { expect{account.authentication}.to raise_error Yt::Errors::Unauthorized }
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
context 'given a redirect URI and an authorization code' do
|
37
|
-
let(:attrs) { {authorization_code: authorization_code, redirect_uri: 'http://localhost/'} }
|
38
|
-
|
39
|
-
context 'that is valid' do
|
40
|
-
# cannot be tested "live"
|
41
|
-
end
|
42
|
-
|
43
|
-
context 'that is invalid' do
|
44
|
-
let(:authorization_code) { rand(36**20).to_s(36) }
|
45
|
-
it { expect{account.authentication}.to raise_error Yt::Errors::Unauthorized }
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
context 'given an access token' do
|
50
|
-
let(:attrs) { {access_token: access_token, expires_at: expires_at} }
|
51
|
-
|
52
|
-
context 'that is valid' do
|
53
|
-
let(:access_token) { $account.access_token }
|
54
|
-
|
55
|
-
context 'that does not have an expiration date' do
|
56
|
-
let(:expires_at) { nil }
|
57
|
-
it { expect(account.authentication).to be_a Yt::Authentication }
|
58
|
-
end
|
59
|
-
|
60
|
-
context 'that has not expired' do
|
61
|
-
let(:expires_at) { 1.day.from_now.to_s }
|
62
|
-
it { expect(account.authentication).to be_a Yt::Authentication }
|
63
|
-
end
|
64
|
-
|
65
|
-
context 'that has expired' do
|
66
|
-
let(:expires_at) { 1.day.ago.to_s }
|
67
|
-
|
68
|
-
context 'and no refresh token' do
|
69
|
-
it { expect{account.authentication}.to raise_error Yt::Errors::MissingAuth }
|
70
|
-
end
|
71
|
-
|
72
|
-
context 'and an invalid refresh token' do
|
73
|
-
before { attrs[:refresh_token] = '--not-a-valid-refresh-token--' }
|
74
|
-
it { expect{account.authentication}.to raise_error Yt::Errors::Unauthorized }
|
75
|
-
end
|
76
|
-
|
77
|
-
context 'and a valid refresh token' do
|
78
|
-
before { attrs[:refresh_token] = ENV['YT_TEST_DEVICE_REFRESH_TOKEN'] }
|
79
|
-
it { expect(account.authentication).to be_a Yt::Authentication }
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
context 'that is invalid' do
|
85
|
-
let(:access_token) { '--not-a-valid-access-token--' }
|
86
|
-
let(:expires_at) { 1.day.from_now }
|
87
|
-
|
88
|
-
context 'and no refresh token' do
|
89
|
-
it { expect{account.channel}.to raise_error Yt::Errors::Unauthorized }
|
90
|
-
end
|
91
|
-
|
92
|
-
context 'and a valid refresh token' do
|
93
|
-
before { attrs[:refresh_token] = ENV['YT_TEST_DEVICE_REFRESH_TOKEN'] }
|
94
|
-
it { expect{account.channel}.not_to raise_error }
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
context 'given scopes' do
|
100
|
-
let(:attrs) { {scopes: ['userinfo.email', 'youtube']} }
|
101
|
-
|
102
|
-
context 'and a redirect_uri' do
|
103
|
-
before { attrs[:redirect_uri] = 'http://localhost/' }
|
104
|
-
|
105
|
-
it { expect{account.authentication}.to raise_error Yt::Errors::MissingAuth }
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
context 'given no token or code' do
|
110
|
-
let(:attrs) { {} }
|
111
|
-
it { expect{account.authentication}.to raise_error Yt::Errors::MissingAuth }
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
describe '#authentication_url' do
|
116
|
-
let(:auth_attrs) { {redirect_uri: 'http://localhost/', scopes: ['userinfo.email', 'userinfo.profile']} }
|
117
|
-
context 'given a redirect URI and scopes' do
|
118
|
-
let(:attrs) { auth_attrs }
|
119
|
-
it { expect(account.authentication_url).to match 'access_type=offline' }
|
120
|
-
|
121
|
-
context 'given a forced approval prompt' do
|
122
|
-
let(:attrs) { auth_attrs.merge force: true }
|
123
|
-
it { expect(account.authentication_url).to match 'approval_prompt=force' }
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
@@ -1,246 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
require 'spec_helper'
|
3
|
-
require 'yt/models/channel'
|
4
|
-
|
5
|
-
describe Yt::Channel, :device_app do
|
6
|
-
subject(:channel) { Yt::Channel.new id: id, auth: $account }
|
7
|
-
|
8
|
-
context 'given someone else’s channel' do
|
9
|
-
let(:id) { 'UCBR8-60-B28hp2BmDPdntcQ' } # YouTube Spotlight
|
10
|
-
|
11
|
-
it 'returns valid metadata' do
|
12
|
-
expect(channel.title).to be_a String
|
13
|
-
expect(channel.description).to be_a String
|
14
|
-
expect(channel.thumbnail_url).to be_a String
|
15
|
-
# expect(channel.published_at).to be_a Time
|
16
|
-
expect(channel.privacy_status).to be_a String
|
17
|
-
expect(channel.view_count).to be_an Integer
|
18
|
-
expect(channel.comment_count).to be_an Integer
|
19
|
-
expect(channel.video_count).to be_an Integer
|
20
|
-
expect(channel.subscriber_count).to be_an Integer
|
21
|
-
expect(channel.subscriber_count_visible?).to be_in [true, false]
|
22
|
-
end
|
23
|
-
|
24
|
-
describe '.videos' do
|
25
|
-
let(:video) { channel.videos.first }
|
26
|
-
|
27
|
-
specify 'returns the videos in the channel without tags or category ID' do
|
28
|
-
expect(video).to be_a Yt::Video
|
29
|
-
expect(video.snippet).not_to be_complete
|
30
|
-
end
|
31
|
-
|
32
|
-
describe '.where(id: *anything*)' do
|
33
|
-
let(:video) { channel.videos.where(id: 'invalid').first }
|
34
|
-
|
35
|
-
specify 'is ignored (all the channel’s videos are returned)' do
|
36
|
-
expect(video).to be_a Yt::Video
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
describe '.where(chart: *anything*)' do
|
41
|
-
let(:video) { channel.videos.where(chart: 'invalid').first }
|
42
|
-
|
43
|
-
specify 'is ignored (all the channel’s videos are returned)' do
|
44
|
-
expect(video).to be_a Yt::Video
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
describe '.includes(:statistics, :status)' do
|
49
|
-
let(:video) { channel.videos.includes(:statistics, :status).first }
|
50
|
-
|
51
|
-
specify 'eager-loads the statistics and status of each video' do
|
52
|
-
expect(video.instance_variable_defined? :@statistics_set).to be true
|
53
|
-
expect(video.instance_variable_defined? :@status).to be true
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
describe '.includes(:content_details)' do
|
58
|
-
let(:video) { channel.videos.includes(:content_details).first }
|
59
|
-
|
60
|
-
specify 'eager-loads the statistics of each video' do
|
61
|
-
expect(video.instance_variable_defined? :@content_detail).to be true
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
describe '.includes(:category)' do
|
66
|
-
let(:video) { channel.videos.includes(:category, :status).first }
|
67
|
-
|
68
|
-
specify 'eager-loads the category (id and title) of each video' do
|
69
|
-
expect(video.instance_variable_defined? :@snippet).to be true
|
70
|
-
expect(video.instance_variable_defined? :@video_category).to be true
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
describe 'when the channel has more than 500 videos' do
|
75
|
-
let(:id) { 'UC0v-tlzsn0QZwJnkiaUSJVQ' } # FBE
|
76
|
-
|
77
|
-
specify 'the estimated and actual number of videos can be retrieved' do
|
78
|
-
# @note: in principle, the following three counters should match, but
|
79
|
-
# in reality +video_count+ and +size+ are only approximations.
|
80
|
-
expect(channel.video_count).to be > 500
|
81
|
-
expect(channel.videos.size).to be > 500
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
describe '.playlists' do
|
87
|
-
describe '.includes(:content_details)' do
|
88
|
-
let(:playlist) { channel.playlists.includes(:content_details).first }
|
89
|
-
|
90
|
-
specify 'eager-loads the content details of each playlist' do
|
91
|
-
expect(playlist.instance_variable_defined? :@content_detail).to be true
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
it { expect(channel.playlists.first).to be_a Yt::Playlist }
|
97
|
-
it { expect{channel.delete_playlists}.to raise_error Yt::Errors::RequestError }
|
98
|
-
|
99
|
-
describe '.related_playlists' do
|
100
|
-
let(:related_playlists) { channel.related_playlists }
|
101
|
-
|
102
|
-
specify 'returns the list of associated playlist (Liked Videos, Uploads, ...)' do
|
103
|
-
expect(related_playlists.first).to be_a Yt::Playlist
|
104
|
-
end
|
105
|
-
|
106
|
-
specify 'includes public related playlists (such as Liked Videos)' do
|
107
|
-
uploads = related_playlists.select{|p| p.title.starts_with? 'Uploads'}
|
108
|
-
expect(uploads).not_to be_empty
|
109
|
-
end
|
110
|
-
|
111
|
-
# NOTE: this test is commented out because today the private playlist is
|
112
|
-
# included on channel.related_playlists, but I couldn't find if this change
|
113
|
-
# has been documented.
|
114
|
-
# specify 'does not includes private playlists (such as Watch Later)' do
|
115
|
-
# watch_later = related_playlists.select{|p| p.title.starts_with? 'Watch'}
|
116
|
-
# expect(watch_later).to be_empty
|
117
|
-
# end
|
118
|
-
end
|
119
|
-
|
120
|
-
specify 'with a public list of subscriptions' do
|
121
|
-
expect(channel.subscribed_channels.first).to be_a Yt::Channel
|
122
|
-
end
|
123
|
-
|
124
|
-
context 'with a hidden list of subscriptions' do
|
125
|
-
let(:id) { 'UCUZHFZ9jIKrLroW8LcyJEQQ' } # YouTube Creators - better make our own one
|
126
|
-
it { expect{channel.subscribed_channels.size}.to raise_error Yt::Errors::Forbidden }
|
127
|
-
end
|
128
|
-
|
129
|
-
# NOTE: These tests are slow because we *must* wait some seconds between
|
130
|
-
# subscribing and unsubscribing to a channel, otherwise YouTube will show
|
131
|
-
# wrong (cached) data, such as a user is subscribed when he is not.
|
132
|
-
context 'that I am not subscribed to', :slow do
|
133
|
-
let(:id) { 'UCCj956IF62FbT7Gouszaj9w' } # BBC
|
134
|
-
before { channel.throttle_subscriptions }
|
135
|
-
|
136
|
-
it { expect(channel.subscribed?).to be false }
|
137
|
-
it { expect(channel.unsubscribe).to be_falsey }
|
138
|
-
it { expect{channel.unsubscribe!}.to raise_error Yt::Errors::RequestError }
|
139
|
-
|
140
|
-
context 'when I subscribe' do
|
141
|
-
before { channel.subscribe }
|
142
|
-
after { channel.unsubscribe }
|
143
|
-
|
144
|
-
it { expect(channel.subscribed?).to be true }
|
145
|
-
it { expect(channel.unsubscribe!).to be_truthy }
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
context 'that I am subscribed to', :slow do
|
150
|
-
let(:id) { 'UCBR8-60-B28hp2BmDPdntcQ' } # YouTube Spotlight
|
151
|
-
before { channel.throttle_subscriptions }
|
152
|
-
|
153
|
-
it { expect(channel.subscribed?).to be true }
|
154
|
-
# NOTE: These tests are commented out because YouTube randomly changed the
|
155
|
-
# behavior of the API without changing the documentation, so subscribing
|
156
|
-
# to a channel you are already subscribed to does not raise an error
|
157
|
-
# anymore.
|
158
|
-
# it { expect(channel.subscribe).to be_falsey }
|
159
|
-
# it { expect{channel.subscribe!}.to raise_error Yt::Errors::RequestError }
|
160
|
-
|
161
|
-
context 'when I unsubscribe' do
|
162
|
-
before { channel.unsubscribe }
|
163
|
-
after { channel.subscribe }
|
164
|
-
|
165
|
-
it { expect(channel.subscribed?).to be false }
|
166
|
-
it { expect(channel.subscribe!).to be_truthy }
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
context 'given my own channel' do
|
172
|
-
let(:id) { $account.channel.id }
|
173
|
-
let(:title) { 'Yt Test <title>' }
|
174
|
-
let(:description) { 'Yt Test <description>' }
|
175
|
-
let(:tags) { ['Yt Test Tag 1', 'Yt Test <Tag> 2'] }
|
176
|
-
let(:privacy_status) { 'unlisted' }
|
177
|
-
let(:params) { {title: title, description: description, tags: tags, privacy_status: privacy_status} }
|
178
|
-
|
179
|
-
specify 'subscriptions can be listed (hidden or public)' do
|
180
|
-
expect(channel.subscriptions.size).to be
|
181
|
-
end
|
182
|
-
|
183
|
-
describe 'playlists can be deleted', rate_limited: true do
|
184
|
-
let(:title) { "Yt Test Delete All Playlists #{rand}" }
|
185
|
-
before { $account.create_playlist params }
|
186
|
-
|
187
|
-
it { expect(channel.delete_playlists title: %r{#{params[:title]}}).to eq [true] }
|
188
|
-
it { expect(channel.delete_playlists params).to eq [true] }
|
189
|
-
it { expect{channel.delete_playlists params}.to change{sleep 1; channel.playlists.count}.by(-1) }
|
190
|
-
end
|
191
|
-
|
192
|
-
# Can't subscribe to your own channel.
|
193
|
-
it { expect{channel.subscribe!}.to raise_error Yt::Errors::RequestError }
|
194
|
-
it { expect(channel.subscribe).to be_falsey }
|
195
|
-
|
196
|
-
it 'returns valid reports for channel-related metrics' do
|
197
|
-
# Some reports are only available to Content Owners.
|
198
|
-
# See content owner test for more details about what the methods return.
|
199
|
-
expect{channel.views}.not_to raise_error
|
200
|
-
expect{channel.comments}.not_to raise_error
|
201
|
-
expect{channel.likes}.not_to raise_error
|
202
|
-
expect{channel.dislikes}.not_to raise_error
|
203
|
-
expect{channel.shares}.not_to raise_error
|
204
|
-
expect{channel.subscribers_gained}.not_to raise_error
|
205
|
-
expect{channel.subscribers_lost}.not_to raise_error
|
206
|
-
expect{channel.videos_added_to_playlists}.not_to raise_error
|
207
|
-
expect{channel.videos_removed_from_playlists}.not_to raise_error
|
208
|
-
expect{channel.estimated_minutes_watched}.not_to raise_error
|
209
|
-
expect{channel.average_view_duration}.not_to raise_error
|
210
|
-
expect{channel.average_view_percentage}.not_to raise_error
|
211
|
-
expect{channel.annotation_clicks}.not_to raise_error
|
212
|
-
expect{channel.annotation_click_through_rate}.not_to raise_error
|
213
|
-
expect{channel.annotation_close_rate}.not_to raise_error
|
214
|
-
expect{channel.card_impressions}.not_to raise_error
|
215
|
-
expect{channel.card_clicks}.not_to raise_error
|
216
|
-
expect{channel.card_click_rate}.not_to raise_error
|
217
|
-
expect{channel.card_teaser_impressions}.not_to raise_error
|
218
|
-
expect{channel.card_teaser_clicks}.not_to raise_error
|
219
|
-
expect{channel.card_teaser_click_rate}.not_to raise_error
|
220
|
-
expect{channel.viewer_percentage}.not_to raise_error
|
221
|
-
expect{channel.estimated_revenue}.to raise_error Yt::Errors::Unauthorized
|
222
|
-
expect{channel.ad_impressions}.to raise_error Yt::Errors::Unauthorized
|
223
|
-
expect{channel.monetized_playbacks}.to raise_error Yt::Errors::Unauthorized
|
224
|
-
expect{channel.playback_based_cpm}.to raise_error Yt::Errors::Unauthorized
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
context 'given an unknown channel' do
|
229
|
-
let(:id) { 'not-a-channel-id' }
|
230
|
-
|
231
|
-
it { expect{channel.snippet}.to raise_error Yt::Errors::NoItems }
|
232
|
-
it { expect{channel.status}.to raise_error Yt::Errors::NoItems }
|
233
|
-
it { expect{channel.statistics_set}.to raise_error Yt::Errors::NoItems }
|
234
|
-
it { expect{channel.subscribe}.to raise_error Yt::Errors::RequestError }
|
235
|
-
|
236
|
-
describe 'starting with UC' do
|
237
|
-
let(:id) { 'UC-not-a-channel-id' }
|
238
|
-
|
239
|
-
# NOTE: This test is just a reflection of YouTube irrational behavior of
|
240
|
-
# returns 0 results if the name of an unknown channel starts with UC, but
|
241
|
-
# returning 100,000 results otherwise (ignoring the channel filter).
|
242
|
-
it { expect(channel.videos.count).to be_zero }
|
243
|
-
it { expect(channel.videos.size).to be_zero }
|
244
|
-
end
|
245
|
-
end
|
246
|
-
end
|