yt 0.25.13 → 0.32.2

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -3,11 +3,9 @@ require 'yt/errors/request_error'
3
3
  module Yt
4
4
  module Errors
5
5
  class Forbidden < RequestError
6
- private
7
-
8
6
  def explanation
9
7
  'A request to YouTube API was considered forbidden by the server'
10
8
  end
11
9
  end
12
10
  end
13
- end
11
+ end
@@ -3,11 +3,9 @@ require 'yt/errors/request_error'
3
3
  module Yt
4
4
  module Errors
5
5
  class NoItems < RequestError
6
- private
7
-
8
6
  def explanation
9
7
  'A request to YouTube API returned no items but some were expected'
10
8
  end
11
9
  end
12
10
  end
13
- end
11
+ end
@@ -19,6 +19,10 @@ module Yt
19
19
  response_body.fetch 'error', {}
20
20
  end
21
21
 
22
+ def description
23
+ response_body.fetch 'error_description', {}
24
+ end
25
+
22
26
  def reasons
23
27
  case kind
24
28
  when Hash then kind.fetch('errors', []).map{|e| e['reason']}
@@ -26,12 +30,15 @@ module Yt
26
30
  end
27
31
  end
28
32
 
29
- private
30
-
31
33
  def explanation
32
34
  'A request to YouTube API failed'
33
35
  end
34
36
 
37
+ def response_body
38
+ json['response_body'].is_a?(Hash) ? json['response_body'] : {}
39
+ end
40
+
41
+ private
35
42
 
36
43
  def details
37
44
  <<-MSG.gsub(/^ {8}/, '')
@@ -56,10 +63,6 @@ module Yt
56
63
  def more_details
57
64
  end
58
65
 
59
- def response_body
60
- json['response_body'].is_a?(Hash) ? json['response_body'] : {}
61
- end
62
-
63
66
  def request_curl
64
67
  json['request_curl']
65
68
  end
@@ -71,4 +74,4 @@ module Yt
71
74
  end
72
75
 
73
76
  Error = Errors::RequestError
74
- end
77
+ end
@@ -3,11 +3,9 @@ require 'yt/errors/request_error'
3
3
  module Yt
4
4
  module Errors
5
5
  class ServerError < RequestError
6
- private
7
-
8
6
  def explanation
9
7
  'A request to YouTube API caused an unexpected server error'
10
8
  end
11
9
  end
12
10
  end
13
- end
11
+ end
@@ -4,12 +4,12 @@ require 'yt/config'
4
4
  module Yt
5
5
  module Errors
6
6
  class Unauthorized < RequestError
7
- private
8
-
9
7
  def explanation
10
8
  'A request to YouTube API was sent without a valid authentication'
11
9
  end
12
10
 
11
+ private
12
+
13
13
  def more_details
14
14
  if [Yt.configuration.client_id, Yt.configuration.api_key].none?
15
15
  <<-MSG.gsub(/^ {10}/, '')
@@ -47,4 +47,4 @@ module Yt
47
47
  end
48
48
  end
49
49
  end
50
- end
50
+ end
@@ -160,6 +160,11 @@ module Yt
160
160
  # upload videos using the resumable upload protocol.
161
161
  has_many :resumable_sessions
162
162
 
163
+ # @!attribute [r] video_groups
164
+ # @return [Yt::Collections::VideoGroups] the video-groups created by the
165
+ # account.
166
+ has_many :video_groups
167
+
163
168
  ### PRIVATE API ###
164
169
 
165
170
  has_authentication
@@ -180,6 +185,13 @@ module Yt
180
185
  {for_mine: true}
181
186
  end
182
187
 
188
+ # @private
189
+ # Tells `has_many :video_groups` that content_owner.groups should return
190
+ # all the video-groups *owned by* the account
191
+ def video_groups_params
192
+ {mine: true}
193
+ end
194
+
183
195
  # @private
184
196
  # Tells `has_many :resumable_sessions` what path to hit to upload a file.
185
197
  def upload_path
@@ -19,9 +19,9 @@ module Yt
19
19
  true
20
20
  end
21
21
 
22
- def ad_formats
23
- @data['adFormats']
24
- end
22
+ has_attribute :ad_formats
23
+ has_attribute :ad_breaks
24
+ has_attribute :tp_ad_server_video_id
25
25
 
26
26
  private
27
27
 
@@ -35,4 +35,4 @@ module Yt
35
35
  end
36
36
  end
37
37
  end
38
- end
38
+ end
@@ -0,0 +1,23 @@
1
+ require 'yt/models/base'
2
+
3
+ module Yt
4
+ module Models
5
+ # Provides methods to interact with YouTube Analytics bulk reports.
6
+ # @see https://developers.google.com/youtube/reporting/v1/reference/rest/v1/jobs.reports
7
+ class BulkReport < Base
8
+ # @private
9
+ attr_reader :auth
10
+
11
+ has_attribute :id
12
+ has_attribute :start_time, type: Time
13
+ has_attribute :end_time, type: Time
14
+ has_attribute :download_url
15
+
16
+ # @private
17
+ def initialize(options = {})
18
+ @data = options.fetch(:data, {})
19
+ @auth = options[:auth]
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ require 'yt/models/base'
2
+
3
+ module Yt
4
+ module Models
5
+ # Provides methods to interact with YouTube Analytics bulk report jobs.
6
+ # @see https://developers.google.com/youtube/reporting/v1/reference/rest/v1/jobs
7
+ class BulkReportJob < Base
8
+ # @private
9
+ attr_reader :id, :auth, :report_type_id
10
+
11
+ # @private
12
+ def initialize(options = {})
13
+ @id = options[:id]
14
+ @auth = options[:auth]
15
+ @report_type_id = options[:report_type_id]
16
+ end
17
+
18
+ # @!attribute [r] bulk_reports
19
+ # @return [Yt::Collections::BulkReports] the bulk reports of this job.
20
+ has_many :bulk_reports
21
+ end
22
+ end
23
+ end
@@ -114,9 +114,6 @@ module Yt
114
114
  # @macro report_by_channel_dimensions
115
115
  has_report :views, Integer
116
116
 
117
- # @macro report_by_day
118
- has_report :uniques, Integer
119
-
120
117
  # @macro report_by_channel_dimensions
121
118
  has_report :estimated_minutes_watched, Integer
122
119
 
@@ -141,12 +138,6 @@ module Yt
141
138
  # @macro report_by_day_and_country
142
139
  has_report :subscribers_lost, Integer
143
140
 
144
- # @macro report_by_day_and_country
145
- has_report :favorites_added, Integer
146
-
147
- # @macro report_by_day_and_country
148
- has_report :favorites_removed, Integer
149
-
150
141
  # @macro report_by_day_and_country
151
142
  has_report :videos_added_to_playlists, Integer
152
143
 
@@ -168,11 +159,29 @@ module Yt
168
159
  # @macro report_by_day_and_state
169
160
  has_report :annotation_close_rate, Float
170
161
 
162
+ # @macro report_by_day_and_state
163
+ has_report :card_impressions, Integer
164
+
165
+ # @macro report_by_day_and_state
166
+ has_report :card_clicks, Integer
167
+
168
+ # @macro report_by_day_and_state
169
+ has_report :card_click_rate, Float
170
+
171
+ # @macro report_by_day_and_state
172
+ has_report :card_teaser_impressions, Integer
173
+
174
+ # @macro report_by_day_and_state
175
+ has_report :card_teaser_clicks, Integer
176
+
177
+ # @macro report_by_day_and_state
178
+ has_report :card_teaser_click_rate, Float
179
+
171
180
  # @macro report_by_day_and_country
172
- has_report :earnings, Float
181
+ has_report :estimated_revenue, Float
173
182
 
174
183
  # @macro report_by_day_and_country
175
- has_report :impressions, Integer
184
+ has_report :ad_impressions, Integer
176
185
 
177
186
  # @macro report_by_day_and_country
178
187
  has_report :monetized_playbacks, Integer
@@ -305,4 +314,4 @@ module Yt
305
314
  end
306
315
  end
307
316
  end
308
- end
317
+ end
@@ -5,12 +5,13 @@ module Yt
5
5
  # Provides methods to interact with YouTube ContentID claims.
6
6
  # @see https://developers.google.com/youtube/partner/docs/v1/claims
7
7
  class Claim < Base
8
- attr_reader :auth
8
+ attr_reader :auth, :data
9
9
 
10
10
  def initialize(options = {})
11
11
  @data = options[:data]
12
12
  @id = options[:id]
13
13
  @auth = options[:auth]
14
+ @asset = options[:asset] if options[:asset]
14
15
  end
15
16
 
16
17
  # @!attribute [r] claim_history
@@ -113,6 +114,16 @@ module Yt
113
114
  content_type == 'audiovisual'
114
115
  end
115
116
 
117
+ # @return [String] the source of the claim
118
+ def source
119
+ @data.fetch('origin', {})['source']
120
+ end
121
+
122
+ # @return [Yt::Models::Asset] the asset of the claim
123
+ def asset
124
+ @asset
125
+ end
126
+
116
127
  # @return [Time] the date and time that the claim was created.
117
128
  has_attribute :created_at, type: Time, from: :time_created
118
129
 
@@ -153,4 +164,4 @@ module Yt
153
164
  end
154
165
  end
155
166
  end
156
- end
167
+ end
@@ -0,0 +1,37 @@
1
+ require 'yt/models/resource'
2
+
3
+ module Yt
4
+ module Models
5
+ # Provides methods to interact with YouTube comment.
6
+ # @see https://developers.google.com/youtube/v3/docs/comments
7
+ class Comment < Resource
8
+
9
+ ### SNIPPET ###
10
+
11
+ # @!attribute [r] video_id
12
+ # @return [String] the ID of the video that the comment refers to.
13
+ delegate :video_id, to: :snippet
14
+
15
+ # @!attribute [r] author_display_name
16
+ # @return [String] the display name of the user who posted the comment.
17
+ delegate :author_display_name, to: :snippet
18
+
19
+ # @!attribute [r] text_display
20
+ # @return [String] the comment's text.
21
+ delegate :text_display, to: :snippet
22
+
23
+ # @!attribute [r] parent_id
24
+ # @return [String] the unique ID of the parent comment. This property is only
25
+ # set if the comment was submitted as a reply to another comment.
26
+ delegate :parent_id, to: :snippet
27
+
28
+ # @!attribute [r] like_count
29
+ # @return [Integer] the total number of likes (positive ratings) the comment has received.
30
+ delegate :like_count, to: :snippet
31
+
32
+ # @!attribute [r] updated_at
33
+ # @return [Time] the date and time when the comment was last updated.
34
+ delegate :updated_at, to: :snippet
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,50 @@
1
+ require 'yt/models/resource'
2
+
3
+ module Yt
4
+ module Models
5
+ # Provides methods to interact with YouTube comment thread.
6
+ # @see https://developers.google.com/youtube/v3/docs/commentThreads
7
+ class CommentThread < Resource
8
+
9
+ ### SNIPPET ###
10
+
11
+ # @!attribute [r] video_id
12
+ # @return [String] the ID of the video that the comment thread referto, if
13
+ # any. If this property is not present or does not have a value, then the
14
+ # thread applies to the channel and not to a specific video.
15
+ delegate :video_id, to: :snippet
16
+
17
+ # @!attribute [r] total_reply_count
18
+ # @return [String] The total number of replies that have been submitted
19
+ # in response to the top level comment.
20
+ delegate :total_reply_count, to: :snippet
21
+
22
+ # @return [Boolean] whether the thread, including all of its comments and
23
+ # comment replies, is visible to all YouTube users.
24
+ delegate :public?, to: :snippet
25
+
26
+ # @return [Boolean] whether the current viewer can reply to the thread.
27
+ delegate :can_reply?, to: :snippet
28
+
29
+ # @!attribute [r] top_level_comment
30
+ # @return [Yt::TopLevelComment] the top level comment object.
31
+ delegate :top_level_comment, to: :snippet
32
+
33
+ # @!attribute [r] text_display
34
+ # @return [String] the top level comment's display text.
35
+ delegate :text_display, to: :top_level_comment
36
+
37
+ # @!attribute [r] author_display_name
38
+ # @return [String] the top level comment's author name.
39
+ delegate :author_display_name, to: :top_level_comment
40
+
41
+ # @!attribute [r] like_count
42
+ # @return [String] the top level comment's likes count.
43
+ delegate :like_count, to: :top_level_comment
44
+
45
+ # @!attribute [r] updated_at
46
+ # @return [String] the top level comment's last updated time.
47
+ delegate :updated_at, to: :top_level_comment
48
+ end
49
+ end
50
+ end
@@ -29,6 +29,12 @@ module Yt
29
29
  content_rating['ytRating']
30
30
  end
31
31
 
32
+ # @return [<String>] the length of the video as an ISO 8601 time, HH:MM:SS.
33
+ def length
34
+ hh, mm, ss = duration / 3600, duration / 60 % 60, duration % 60
35
+ [hh, mm, ss].map{|t| t.to_s.rjust(2,'0')}.join(':')
36
+ end
37
+
32
38
  private
33
39
 
34
40
  # @return [Integer] the duration of the resource as reported by YouTube.
@@ -27,9 +27,23 @@ module Yt
27
27
  # @return [Yt::Collections::Policies] the policies saved by the content owner.
28
28
  has_many :policies
29
29
 
30
+ # @return [String] The display name of the content owner.
31
+ attr_reader :display_name
32
+
33
+ # @!attribute [r] video_groups
34
+ # @return [Yt::Collections::VideoGroups] the video-groups managed by the
35
+ # content owner.
36
+ has_many :video_groups
37
+
38
+ # @!attribute [r] bulk_report_jobs
39
+ # @return [Yt::Collections::BulkReportJobs] the bulk reporting jobs managed by the
40
+ # content owner.
41
+ has_many :bulk_report_jobs
42
+
30
43
  def initialize(options = {})
31
44
  super options
32
45
  @owner_name = options[:owner_name]
46
+ @display_name = options[:display_name]
33
47
  end
34
48
 
35
49
  def create_reference(params = {})
@@ -43,6 +57,22 @@ module Yt
43
57
  def create_claim(params = {})
44
58
  claims.insert params
45
59
  end
60
+
61
+ ### PRIVATE API ###
62
+
63
+ # @private
64
+ # Tells `has_many :videos` that account.videos should return all the
65
+ # videos *on behalf of* the content owner (public, private, unlisted).
66
+ def videos_params
67
+ {for_content_owner: true, on_behalf_of_content_owner: @owner_name}
68
+ end
69
+
70
+ # @private
71
+ # Tells `has_many :video_groups` that content_owner.video_groups should
72
+ # return all the video-groups *on behalf of* the content owner
73
+ def video_groups_params
74
+ {on_behalf_of_content_owner: @owner_name}
75
+ end
46
76
  end
47
77
  end
48
- end
78
+ end