yt 0.19.0 → 0.20.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 17691684dae81110d7d3ff39e8952823deedc5ac
4
- data.tar.gz: a2438b53994ef551b3525a310db27990695a7f1d
3
+ metadata.gz: 5fe27d147e90b10dde52f153efedf061043b9788
4
+ data.tar.gz: fb07f986240215dba34f01d78762503471cf61a5
5
5
  SHA512:
6
- metadata.gz: 9994436e29b6ef5b5bc3533db28e5f40e2839948076f30cac3794769b4e962cd0dee3dc88e4f1f52641420cd401b62070d8cc8bcf9aae4eabf349b397bfa6408
7
- data.tar.gz: 98f99214f24da915e60247d4192579b93b5579e5e16e83cde009bd017f21c46c5a9a6c22a7451b291c1e4afd69fc130570b29fd419b37b1d96d9148a0469e6fb
6
+ metadata.gz: 0c20df4b1ad2ac9420d3bd183e04892f9cffaaefb3989330794ce8004de7f06c8ce6b52260980582f2cc22e5239871c24aa868156d27bd488465184dd8940da3
7
+ data.tar.gz: b4ec8a79ced4d3e5535a68daa4ae56f593d70e8bd86d20c0c3ef041ca85c88266b77f2f787a7fe1bf08fd04b61b4738ffc02ab3b93d5cce8699ba60c3c7d701b
@@ -6,6 +6,23 @@ 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.20.0 - 2015-04-29
10
+
11
+ **How to upgrade**
12
+
13
+ If your code doesn’t use any of the following constants that were public but
14
+ undocumented, then you are good to go.
15
+
16
+ If it does, then you should redefine those constants in your own app, since
17
+ it’s not Yt’s goal to validate the values posted to YouTube API.
18
+
19
+ * [REMOVAL] Remove `Asset#STATUSES` (was `%q(active inactive pending)`).
20
+ * [REMOVAL] Remove `Claim#STATUSES` (was `%q(active appealed disputed inactive pending potential takedown unknown)`).
21
+ * [REMOVAL] Remove `Claim#CONTENT_TYPES` (was `%q(audio video audiovisual)`).
22
+ * [REMOVAL] Remove `Reference#STATUSES` (was `%q(activating active checking computing_fingerprint deleted duplicate_on_hold inactive live_streaming_processing urgent_reference_processing)`).
23
+ * [REMOVAL] Remove `Reference#CONTENT_TYPES` (was `%q(audio video audiovisual)`).
24
+ * [REMOVAL] Remove `Status#PRIVACY_STATUSES` (was `%q(private public unlisted)`).
25
+
9
26
  ## 0.19.0 - 2015-04-28
10
27
 
11
28
  **How to upgrade**
data/README.md CHANGED
@@ -41,7 +41,7 @@ To install on your system, run
41
41
 
42
42
  To use inside a bundled Ruby project, add this line to the Gemfile:
43
43
 
44
- gem 'yt', '~> 0.19.0'
44
+ gem 'yt', '~> 0.20.0'
45
45
 
46
46
  Since the gem follows [Semantic Versioning](http://semver.org),
47
47
  indicating the full version in your Gemfile (~> *major*.*minor*.*patch*)
@@ -1,12 +1,10 @@
1
1
  module Yt
2
2
  module Associations
3
+ # @private
3
4
  # Provides methods to access the analytics reports of a resource.
4
- #
5
- # YouTube resources with reports are: {Yt::Models::Channel channels} and
6
- # {Yt::Models::Channel videos}.
7
5
  module HasReports
8
6
  # @!macro [new] report
9
- # Returns the $1 of the video grouped by the given dimension.
7
+ # Returns the $1 grouped by the given dimension.
10
8
  # @!method $1(options = {})
11
9
  # @param [Hash] options the time-range and dimensions for the $1.
12
10
  # @option options [#to_date] :since The first day of the time-range.
@@ -14,65 +12,103 @@ module Yt
14
12
  # @option options [#to_date] :until The last day of the time-range.
15
13
  # Also aliased as +:to+.
16
14
 
17
- # @!macro [new] daily_report
18
- # @option options [Symbol] :by (:day) The dimension to collect $1 by.
19
- # Accepted values are: +:day+.
20
- # @return [Hash<Date, Float>] if grouped by day, the $1 of the video
15
+ # @!macro [new] report_with_day
16
+ # @return [Hash<Date, Float>] if grouped by day, the $1
21
17
  # for each day in the time-range.
22
- # @example Get the video’s $1 for each day of last week:
23
- # video.$1 since: 2.weeks.ago, until: 1.week.ago, by: :day
18
+ # @example Get the $1 for each day of last week:
19
+ # resource.$1 since: 2.weeks.ago, until: 1.week.ago, by: :day
24
20
  # # => {Wed, 8 May 2014 => 12.0, Thu, 9 May 2014 => 34.2, …}
25
21
  # @macro report
26
22
 
27
- # @!macro [new] views_report
23
+ # @!macro [new] report_by_day
28
24
  # @option options [Symbol] :by (:day) The dimension to collect $1 by.
29
- # Accepted values are: +:day+, +:traffic_source+,
30
- # +:playback_location+,+:embedded_player_location+, +:related_video+.
31
- # @return [Hash<Date, Float>] if grouped by day, the $1 of the video
32
- # for each day in the time-range.
33
- # @example Get the video’s $1 for each day of last week:
34
- # video.$1 since: 2.weeks.ago, until: 1.week.ago, by: :day
35
- # # => {Wed, 8 May 2014 => 12.0, Thu, 9 May 2014 => 34.2, …}
36
- # @return [Hash<Symbol, Float>] if grouped by traffic source, the
37
- # $1 of the video for each traffic source.
38
- # @example Get yesterday’s video’s $1 grouped by traffic source:
39
- # video.$1 from: 1.day.ago, to: 1.day.ago, by: :traffic_source
40
- # # => {advertising: 53.0, channel: 7.0, …}
25
+ # Accepted values are: +:day+.
26
+ # @macro report_with_day
27
+
28
+ # @!macro [new] report_with_video_dimensions
41
29
  # @return [Hash<Symbol, Float>] if grouped by playback location, the
42
- # $1 of the video for each traffic playback location.
43
- # @example Get yesterday’s video’s $1 grouped by playback location:
44
- # video.$1 from: 1.day.ago, to: 1.day.ago, by: :playback_location
30
+ # $1 for each traffic playback location.
31
+ # @example Get yesterday’s $1 grouped by playback location:
32
+ # resource.$1 from: 1.day.ago, to: 1.day.ago, by: :playback_location
45
33
  # # => {embedded: 53.0, watch: 467.0, …}
34
+ # @return [Hash<Yt::Video, Float>] if grouped by related video, the
35
+ # $1 for each related video.
36
+ # @example Get yesterday’s $1 by related video:
37
+ # resource.$1 from: 1.day.ago, to: 1.day.ago, by: :related_video
38
+ # # => {#<Yt::Video @id=…> => 33.0, #<Yt::Video @id=…> => 12.0, …}
39
+ # @return [Hash<Yt::Video, Float>] if grouped by device type, the
40
+ # $1 for each device type.
41
+ # @example Get yesterday’s $1 by device type:
42
+ # resource.$1 from: 1.day.ago, to: 1.day.ago, by: :device_type
43
+ # # => {mobile: 133.0, tv: 412.0, …}
44
+ # @return [Hash<Yt::Video, Float>] if grouped by traffic source, the
45
+ # $1 for each traffic source.
46
+ # @example Get yesterday’s $1 by traffic source:
47
+ # resource.$1 from: 1.day.ago, to: 1.day.ago, by: :traffic_source
48
+ # # => {advertising: 543.0, playlist: 92.0, …}
49
+ # @macro report_with_day
50
+
51
+ # @!macro [new] report_by_video_dimensions
52
+ # @option options [Symbol] :by (:day) The dimension to collect $1 by.
53
+ # Accepted values are: +:day+, +:traffic_source+,
54
+ # +:playback_location+, +:related_video+, +:embedded_player_location+.
46
55
  # @return [Hash<Symbol, Float>] if grouped by embedded player location,
47
- # the $1 of the video for each embedded player location.
48
- # @example Get yesterday’s video’s $1 by embedded player location:
49
- # video.$1 from: 1.day.ago, to: 1.day.ago, by: :embedded_player_location
56
+ # the $1 for each embedded player location.
57
+ # @example Get yesterday’s $1 by embedded player location:
58
+ # resource.$1 from: 1.day.ago, to: 1.day.ago, by: :embedded_player_location
50
59
  # # => {"fullscreen.net" => 92.0, "yahoo.com" => 14.0, …}
51
- # @return [Hash<Yt::Video, Float>] if grouped by related video, the
52
- # $1 of the video for each related video.
53
- # @example Get yesterday’s video’s $1 by related video:
54
- # video.$1 from: 1.day.ago, to: 1.day.ago, by: :related_video
60
+ # @macro report_with_video_dimensions
61
+
62
+ # @!macro [new] report_with_channel_dimensions
63
+ # @return [Hash<Yt::Video, Float>] if grouped by video, the
64
+ # $1 for each video.
65
+ # @example Get yesterday’s $1 by video:
66
+ # resource.$1 from: 1.day.ago, to: 1.day.ago, by: :video
55
67
  # # => {#<Yt::Video @id=…> => 33.0, #<Yt::Video @id=…> => 12.0, …}
56
- # @macro report
68
+ # @return [Hash<Yt::Video, Float>] if grouped by playlist, the
69
+ # $1 for each playlist.
70
+ # @example Get yesterday’s $1 by playlist:
71
+ # resource.$1 from: 1.day.ago, to: 1.day.ago, by: :playlist
72
+ # # => {#<Yt::Video @id=…> => 33.0, #<Yt::Video @id=…> => 12.0, …}
73
+ # @macro report_with_video_dimensions
74
+
75
+ # @!macro [new] report_by_channel_dimensions
76
+ # @option options [Symbol] :by (:day) The dimension to collect $1 by.
77
+ # Accepted values are: +:day+, +:traffic_source+,
78
+ # +:playback_location+, +:related_video+, +:video+,
79
+ # +:playlist+, +:embedded_player_location+.
80
+ # @return [Hash<Symbol, Float>] if grouped by embedded player location,
81
+ # the $1 for each embedded player location.
82
+ # @example Get yesterday’s $1 by embedded player location:
83
+ # resource.$1 from: 1.day.ago, to: 1.day.ago, by: :embedded_player_location
84
+ # # => {"fullscreen.net" => 92.0, "yahoo.com" => 14.0, …}
85
+ # @macro report_with_channel_dimensions
86
+
87
+ # @!macro [new] report_by_playlist_dimensions
88
+ # @option options [Symbol] :by (:day) The dimension to collect $1 by.
89
+ # Accepted values are: +:day+, +:traffic_source+,
90
+ # +:playback_location+, +:related_video+, +:video+,
91
+ # +:playlist+.
92
+ # @macro report_with_channel_dimensions
57
93
 
58
- # @!macro [new] demographics_report
94
+ # @!macro [new] report_by_gender_and_age_group
59
95
  # @option options [Symbol] :by (:gender_age_group) The dimension to
60
96
  # show viewer percentage by.
61
97
  # Accepted values are: +:gender+, +:age_group+, +:gender_age_group+.
62
- # @return [Hash<Symbol, Float>] if grouped by gender, the video’s
98
+ # @return [Hash<Symbol, Float>] if grouped by gender, the
63
99
  # viewer percentage by gender.
64
- # @example Get yesterday’s video’s viewer percentage by gender:
65
- # video.$1 from: 1.day.ago, to: 1.day.ago, by: :gender
100
+ # @example Get yesterday’s viewer percentage by gender:
101
+ # resource.$1 from: 1.day.ago, to: 1.day.ago, by: :gender
66
102
  # # => {female: 53.0, male: 47.0}
67
- # @return [Hash<String, Float>] if grouped by age group, the video’s
103
+ # @return [Hash<String, Float>] if grouped by age group, the
68
104
  # viewer percentage by age group.
69
- # @example Get yesterday’s video’s $1 grouped by age group:
70
- # video.$1 from: 1.day.ago, to: 1.day.ago, by: :age_group
105
+ # @example Get yesterday’s $1 grouped by age group:
106
+ # resource.$1 from: 1.day.ago, to: 1.day.ago, by: :age_group
71
107
  # # => {"18-24" => 4.54, "35-24" => 12.31, "45-34" => 8.92, …}
72
108
  # @return [Hash<Symbol, [Hash<String, Float>]>] if grouped by gender
73
- # and age group, the video’s viewer percentage by gender/age group.
74
- # @example Get yesterday’s video’s $1 by gender and age group:
75
- # video.$1 from: 1.day.ago, to: 1.day.ago
109
+ # and age group, the viewer percentage by gender/age group.
110
+ # @example Get yesterday’s $1 by gender and age group:
111
+ # resource.$1 from: 1.day.ago, to: 1.day.ago
76
112
  # # => {female: {"18-24" => 12.12, "25-34" => 16.16, …}, male:…}
77
113
  # @macro report
78
114
 
@@ -71,6 +71,7 @@ module Yt
71
71
  timestamps.first < seconds if timestamps.any?
72
72
  end
73
73
 
74
+ # @return [String] the textual content of the annotation.
74
75
  def text
75
76
  @text ||= @data['TEXT'] || ''
76
77
  end
@@ -72,8 +72,6 @@ module Yt
72
72
 
73
73
  # Status
74
74
 
75
- STATUSES = %q(active inactive pending)
76
-
77
75
  # Returns the asset’s status.
78
76
  # @return [String] the asset’s status. Possible values are: +'active'+,
79
77
  # +'inactive'+, +'pending'+.
@@ -2,9 +2,90 @@ require 'yt/models/resource'
2
2
 
3
3
  module Yt
4
4
  module Models
5
- # A channel resource contains information about a YouTube channel.
5
+ # Provides methods to interact with YouTube channels.
6
6
  # @see https://developers.google.com/youtube/v3/docs/channels
7
7
  class Channel < Resource
8
+
9
+ ### SNIPPET ###
10
+
11
+ # @!attribute [r] title
12
+ # @return [String] the channel’s title.
13
+ delegate :title, to: :snippet
14
+
15
+ # @!attribute [r] description
16
+ # @return [String] the channel’s description.
17
+ delegate :description, to: :snippet
18
+
19
+ # Returns the URL of the channel’s thumbnail.
20
+ # @!method thumbnail_url(size = :default)
21
+ # @param [Symbol, String] size The size of the channel’s thumbnail.
22
+ # @return [String] if +size+ is +default+, the URL of a 88x88px image.
23
+ # @return [String] if +size+ is +medium+, the URL of a 240x240px image.
24
+ # @return [String] if +size+ is +high+, the URL of a 800x800px image.
25
+ # @return [nil] if the +size+ is not +default+, +medium+ or +high+.
26
+ delegate :thumbnail_url, to: :snippet
27
+
28
+ # @!attribute [r] published_at
29
+ # @return [Time] the date and time that the channel was created.
30
+ delegate :published_at, to: :snippet
31
+
32
+ ### SUBSCRIPTION ###
33
+
34
+ has_one :subscription
35
+
36
+ # @return [Boolean] whether the account is subscribed to the channel.
37
+ # @raise [Yt::Errors::Unauthorized] if {Resource#auth auth} is not an
38
+ # authenticated Yt::Account.
39
+ def subscribed?
40
+ sleep [(@subscriptions_updated_at || Time.now) - Time.now, 0].max
41
+ subscription.exists?
42
+ rescue Errors::NoItems
43
+ false
44
+ end
45
+
46
+ # Subscribes the authenticated account to the channel.
47
+ # Unlike {#subscribe!}, does not raise an error if already subscribed.
48
+ # @raise [Yt::Errors::Unauthorized] if {Resource#auth auth} is not an
49
+ # authenticated Yt::Account.
50
+ def subscribe
51
+ subscriptions.insert(ignore_errors: true).tap do |subscription|
52
+ throttle_subscriptions
53
+ @subscription = subscription
54
+ end
55
+ end
56
+
57
+ # Subscribes the authenticated account to the channel.
58
+ # Unlike {#subscribe}, raises an error if already subscribed.
59
+ # @raise [Yt::Errors::RequestError] if already subscribed.
60
+ # @raise [Yt::Errors::Unauthorized] if {Resource#auth auth} is not an
61
+ # authenticated Yt::Account.
62
+ def subscribe!
63
+ subscriptions.insert.tap do |subscription|
64
+ throttle_subscriptions
65
+ @subscription = subscription
66
+ end
67
+ end
68
+
69
+ # Unsubscribes the authenticated account from the channel.
70
+ # Unlike {#unsubscribe!}, does not raise an error if already unsubscribed.
71
+ # @raise [Yt::Errors::Unauthorized] if {Resource#auth auth} is not an
72
+ # authenticated Yt::Account.
73
+ def unsubscribe
74
+ unsubscribe! if subscribed?
75
+ end
76
+
77
+ # Unsubscribes the authenticated account from the channel.
78
+ # Unlike {#unsubscribe}, raises an error if already unsubscribed.
79
+ #
80
+ # @raise [Yt::Errors::RequestError] if already unsubscribed.
81
+ # @raise [Yt::Errors::Unauthorized] if {Resource#auth auth} is not an
82
+ # authenticated Yt::Account.
83
+ def unsubscribe!
84
+ subscription.delete.tap{ throttle_subscriptions }
85
+ end
86
+
87
+ ### ASSOCIATIONS ###
88
+
8
89
  # @!attribute [r] videos
9
90
  # @return [Yt::Collections::Videos] the channel’s videos.
10
91
  has_many :videos
@@ -13,168 +94,154 @@ module Yt
13
94
  # @return [Yt::Collections::Playlists] the channel’s playlists.
14
95
  has_many :playlists
15
96
 
16
- # @macro has_report
17
- has_report :earnings
97
+ # @!attribute [r] subscribed_channels
98
+ # @return [Yt::Collections::SubscribedChannels] the channels that this
99
+ # channel is subscribed to.
100
+ # @raise [Yt::Errors::Forbidden] if the owner of the channel has
101
+ # explicitly select the option to keep all subscriptions private.
102
+ has_many :subscribed_channels
103
+
104
+ ### ANALYTICS ###
18
105
 
19
- # @macro has_report
106
+ # @macro report_by_channel_dimensions
20
107
  has_report :views
21
108
 
22
- # @macro has_report
109
+ # @macro report_by_channel_dimensions
110
+ has_report :estimated_minutes_watched
111
+
112
+ # @macro report_by_gender_and_age_group
113
+ has_report :viewer_percentage
114
+
115
+ # @macro report_by_day
23
116
  has_report :comments
24
117
 
25
- # @macro has_report
118
+ # @macro report_by_day
26
119
  has_report :likes
27
120
 
28
- # @macro has_report
121
+ # @macro report_by_day
29
122
  has_report :dislikes
30
123
 
31
- # @macro has_report
124
+ # @macro report_by_day
32
125
  has_report :shares
33
126
 
34
- # @macro has_report
127
+ # @macro report_by_day
35
128
  has_report :subscribers_gained
36
129
 
37
- # @macro has_report
130
+ # @macro report_by_day
38
131
  has_report :subscribers_lost
39
132
 
40
- # @macro has_report
133
+ # @macro report_by_day
41
134
  has_report :favorites_added
42
135
 
43
- # @macro has_report
136
+ # @macro report_by_day
44
137
  has_report :favorites_removed
45
138
 
46
- # @macro has_report
47
- has_report :estimated_minutes_watched
48
-
49
- # @macro has_report
139
+ # @macro report_by_day
50
140
  has_report :average_view_duration
51
141
 
52
- # @macro has_report
142
+ # @macro report_by_day
53
143
  has_report :average_view_percentage
54
144
 
55
- # @macro has_report
56
- has_report :impressions
57
-
58
- # @macro has_report
59
- has_report :monetized_playbacks
60
-
61
- # @macro has_report
145
+ # @macro report_by_day
62
146
  has_report :annotation_clicks
63
147
 
64
- # @macro has_report
148
+ # @macro report_by_day
65
149
  has_report :annotation_click_through_rate
66
150
 
67
- # @macro has_report
151
+ # @macro report_by_day
68
152
  has_report :annotation_close_rate
69
153
 
70
- # @macro has_report
71
- has_report :viewer_percentage
154
+ # @macro report_by_day
155
+ has_report :earnings
156
+
157
+ # @macro report_by_day
158
+ has_report :impressions
159
+
160
+ # @macro report_by_day
161
+ has_report :monetized_playbacks
162
+
163
+ ### STATISTICS ###
72
164
 
73
- # @!attribute [r] statistics_set
74
- # @return [Yt::Models::StatisticsSet] the statistics for the video.
75
165
  has_one :statistics_set
76
- delegate :view_count, :comment_count, :video_count, :subscriber_count,
77
- :subscriber_count_visible?, to: :statistics_set
78
166
 
79
- # @!attribute [r] content_owner_detail
80
- # @return [Yt::Models::ContentOwnerDetail] the video’s content owner
81
- # details.
82
- has_one :content_owner_detail
83
- delegate :content_owner, :linked_at, to: :content_owner_detail
167
+ # @!attribute [r] view_count
168
+ # @return [Integer] the number of times the channel has been viewed.
169
+ delegate :view_count, to: :statistics_set
84
170
 
85
- # @!attribute [r] subscribed_channels
86
- # @return [Yt::Collections::SubscribedChannels] the channels that the channel is subscribed to.
87
- # @raise [Yt::Errors::Forbidden] if the owner of the channel has
88
- # explicitly select the option to keep all subscriptions private.
89
- has_many :subscribed_channels
171
+ # @!attribute [r] comment_count
172
+ # @return [Integer] the number of comments for the channel.
173
+ delegate :comment_count, to: :statistics_set
90
174
 
91
- # @!attribute [r] subscription
92
- # @return [Yt::Models::Subscription] the channel’s subscription by auth.
93
- # @raise [Yt::Errors::NoItems] if {Resource#auth auth} is not
94
- # subscribed to the channel.
95
- # @raise [Yt::Errors::Unauthorized] if {Resource#auth auth} does not
96
- # return an authenticated account.
97
- has_one :subscription
175
+ # @!attribute [r] video_count
176
+ # @return [Integer] the number of videos uploaded to the channel.
177
+ delegate :video_count, to: :statistics_set
98
178
 
99
- # Override Resource's new to set statistics as well
100
- # if the response includes them
101
- def initialize(options = {})
102
- super options
103
- if options[:statistics]
104
- @statistics_set = StatisticsSet.new data: options[:statistics]
105
- end
106
- end
179
+ # @!attribute [r] subscriber_count
180
+ # @return [Integer] the number of subscriber the channel has.
181
+ delegate :subscriber_count, to: :statistics_set
107
182
 
108
- # Returns whether the authenticated account is subscribed to the channel.
109
- #
110
- # This method requires {Resource#auth auth} to return an
111
- # authenticated instance of {Yt::Account}.
112
- # @return [Boolean] whether the account is subscribed to the channel.
113
- # @raise [Yt::Errors::Unauthorized] if {Resource#auth auth} does not
114
- # return an authenticated account.
115
- def subscribed?
116
- sleep [(@subscriptions_updated_at || Time.now) - Time.now, 0].max
117
- subscription.exists?
118
- rescue Errors::NoItems
119
- false
183
+ # @return [Boolean] whether the number of subscribers is publicly visible.
184
+ def subscriber_count_visible?
185
+ statistics_set.hidden_subscriber_count == false
120
186
  end
121
187
 
122
- # Unsubscribes the authenticated account from the channel.
123
- # Raises an error if the account was not subscribed.
124
- #
125
- # This method requires {Resource#auth auth} to return an
126
- # authenticated instance of {Yt::Account}.
127
- # @raise [Yt::Errors::RequestError] if {Resource#auth auth} was not
128
- # subscribed to the channel.
129
- # @raise [Yt::Errors::Unauthorized] if {Resource#auth auth} does not
130
- # return an authenticated account.
131
- def unsubscribe!
132
- subscription.delete.tap{ throttle_subscriptions }
133
- end
188
+ ### CONTENT OWNER DETAILS ###
134
189
 
135
- # Unsubscribes the authenticated account from the channel.
136
- # Does not raise an error if the account was not subscribed.
137
- #
138
- # This method requires {Resource#auth auth} to return an
139
- # authenticated instance of {Yt::Account}.
140
- # @raise [Yt::Errors::Unauthorized] if {Resource#auth auth} does not
141
- # return an authenticated account.
142
- def unsubscribe
143
- unsubscribe! if subscribed?
144
- end
190
+ has_one :content_owner_detail
145
191
 
146
- # Subscribes the authenticated account to the channel.
147
- # Raises an error if the account was already subscribed.
148
- #
149
- # This method requires {Resource#auth auth} to return an
150
- # authenticated instance of {Yt::Account}.
151
- # @raise [Yt::Errors::RequestError] if {Resource#auth auth} was already
152
- # subscribed to the channel.
153
- # @raise [Yt::Errors::Unauthorized] if {Resource#auth auth} does not
154
- # return an authenticated account.
155
- def subscribe!
156
- subscriptions.insert.tap do |subscription|
157
- throttle_subscriptions
158
- @subscription = subscription
159
- end
192
+ # The name of the content owner linked to the channel.
193
+ # @!attribute [r] content_owner
194
+ # @return [String] if the channel is partnered, its content owner’s name.
195
+ # @return [nil] if the channel is not partnered or if {Resource#auth auth}
196
+ # is a content owner without permissions to administer the channel.
197
+ # @raise [Yt::Errors::Forbidden] if {Resource#auth auth} does not
198
+ # return an authenticated content owner.
199
+ delegate :content_owner, to: :content_owner_detail
200
+
201
+ # Returns the time the channel was partnered to a content owner.
202
+ # @return [Time] if the channel is partnered, the time when it was linked
203
+ # to its content owner.
204
+ # @return [nil] if the channel is not partnered or if {Resource#auth auth}
205
+ # is a content owner without permissions to administer the channel.
206
+ # @raise [Yt::Errors::Forbidden] if {Resource#auth auth} does not
207
+ # return an authenticated content owner.
208
+ def linked_at
209
+ content_owner_detail.time_linked
160
210
  end
161
211
 
162
- # Subscribes the authenticated account to the channel.
163
- # Does not raise an error if the account was already subscribed.
164
- #
165
- # This method requires {Resource#auth auth} to return an
166
- # authenticated instance of {Yt::Account}.
167
- # @raise [Yt::Errors::Unauthorized] if {Resource#auth auth} does not
168
- # return an authenticated account.
169
- def subscribe
170
- subscriptions.insert(ignore_errors: true).tap do |subscription|
171
- throttle_subscriptions
172
- @subscription = subscription
173
- end
212
+ ### ACTIONS (UPLOAD, UPDATE, DELETE) ###
213
+
214
+ # Deletes the channel’s playlists matching all the given attributes.
215
+ # @return [Array<Boolean>] whether each playlist matching the given
216
+ # attributes was deleted.
217
+ # @raise [Yt::Errors::RequestError] if {Resource#auth auth} is not an
218
+ # authenticated Yt::Account with permissions to update the channel.
219
+ # @param [Hash] attributes the attributes to match the playlists by.
220
+ # @option attributes [<String, Regexp>] :title The playlist’s title.
221
+ # Pass a String for perfect match or a Regexp for advanced match.
222
+ # @option attributes [<String, Regexp>] :description The playlist’s
223
+ # description. Pass a String (perfect match) or a Regexp (advanced).
224
+ # @option attributes [Array<String>] :tags The playlist’s tags.
225
+ # All tags must match exactly.
226
+ # @option attributes [String] :privacy_status The playlist’s privacy
227
+ # status.
228
+ def delete_playlists(attributes = {})
229
+ playlists.delete_all attributes
174
230
  end
175
231
 
176
- def delete_playlists(attrs = {})
177
- playlists.delete_all attrs
232
+ ### PRIVATE API ###
233
+
234
+ # @private
235
+ # Override Resource's new to set statistics as well
236
+ # if the response includes them
237
+ def initialize(options = {})
238
+ super options
239
+ if options[:statistics]
240
+ @statistics_set = StatisticsSet.new data: options[:statistics]
241
+ end
242
+ if options[:content_owner_details]
243
+ @content_owner_detail = ContentOwnerDetail.new data: options[:content_owner_details]
244
+ end
178
245
  end
179
246
 
180
247
  # @private