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
@@ -0,0 +1,16 @@
1
+ module Yt
2
+ module Models
3
+ class GroupInfo < Base
4
+ attr_reader :data
5
+
6
+ def initialize(options = {})
7
+ @data = options[:data]['snippet'].merge options[:data]['contentDetails']
8
+ @auth = options[:auth]
9
+ end
10
+
11
+ has_attribute :title, default: ''
12
+ has_attribute :item_count, type: Integer
13
+ has_attribute :published_at, type: Time
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ require 'yt/models/video'
2
+
3
+ module Yt
4
+ module Models
5
+ class GroupItem < Base
6
+ attr_reader :auth, :data, :video
7
+
8
+ def initialize(options = {})
9
+ @data = options[:data]
10
+ @auth = options[:auth]
11
+ @video = options[:video] if options[:video]
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,7 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  require 'yt/models/base'
4
- require 'yt/models/url'
5
4
 
6
5
  module Yt
7
6
  module Models
@@ -13,7 +12,7 @@ module Yt
13
12
 
14
13
  # @!attribute [r] id
15
14
  # @return [String] the ID that YouTube uses to identify each resource.
16
- has_one :id
15
+ attr_reader :id
17
16
 
18
17
  ### STATUS ###
19
18
 
@@ -43,8 +42,7 @@ module Yt
43
42
 
44
43
  # @private
45
44
  def initialize(options = {})
46
- @url = URL.new(options[:url]) if options[:url]
47
- @id = options[:id] || (@url.id if @url)
45
+ @id = options[:id]
48
46
  @auth = options[:auth]
49
47
  @snippet = Snippet.new(data: options[:snippet]) if options[:snippet]
50
48
  @status = Status.new(data: options[:status]) if options[:status]
@@ -52,12 +50,7 @@ module Yt
52
50
 
53
51
  # @private
54
52
  def kind
55
- @url ? @url.kind.to_s : self.class.to_s.demodulize.underscore
56
- end
57
-
58
- # @private
59
- def username
60
- @url.username if @url
53
+ self.class.to_s.demodulize.underscore
61
54
  end
62
55
 
63
56
  # @private
@@ -0,0 +1,12 @@
1
+ require 'yt/models/base'
2
+
3
+ module Yt
4
+ module Models
5
+ # @private
6
+ class Revocation < Base
7
+ def initialize(options = {})
8
+ @data = options[:data]
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,5 +1,3 @@
1
- require 'yt/models/description'
2
-
3
1
  module Yt
4
2
  module Models
5
3
  # Encapsulates information about the various types of owners of an asset.
@@ -1,4 +1,4 @@
1
- require 'yt/models/description'
1
+ require 'yt/models/comment'
2
2
 
3
3
  module Yt
4
4
  module Models
@@ -8,6 +8,8 @@ module Yt
8
8
  # @see https://developers.google.com/youtube/v3/docs/videos#resource
9
9
  # @see https://developers.google.com/youtube/v3/docs/playlists#resource
10
10
  # @see https://developers.google.com/youtube/v3/docs/playlistItems#resource
11
+ # @see https://developers.google.com/youtube/v3/docs/commentThreads#resource
12
+ # @see https://developers.google.com/youtube/v3/docs/comments#resource
11
13
  class Snippet < Base
12
14
  attr_reader :data
13
15
 
@@ -17,7 +19,7 @@ module Yt
17
19
  end
18
20
 
19
21
  has_attribute :title, default: ''
20
- has_attribute(:description, default: '') {|text| Description.new text}
22
+ has_attribute :description, default: ''
21
23
  has_attribute :published_at, type: Time
22
24
  has_attribute :channel_id
23
25
  has_attribute :channel_title
@@ -28,11 +30,30 @@ module Yt
28
30
  has_attribute :position, type: Integer
29
31
  has_attribute :resource_id, default: {}
30
32
  has_attribute :thumbnails, default: {}
33
+ has_attribute :video_id
34
+ has_attribute :total_reply_count, type: Integer
35
+ has_attribute :author_display_name
36
+ has_attribute :text_display
37
+ has_attribute :parent_id
38
+ has_attribute :like_count, type: Integer
39
+ has_attribute :updated_at, type: Time
31
40
 
32
41
  def thumbnail_url(size = :default)
33
42
  thumbnails.fetch(size.to_s, {})['url']
34
43
  end
35
44
 
45
+ def public?
46
+ @public ||= data.fetch 'isPublic', false
47
+ end
48
+
49
+ def can_reply?
50
+ @can_reply ||= data.fetch 'canReply', false
51
+ end
52
+
53
+ def top_level_comment
54
+ @top_level_comment ||= Yt::Comment.new data['topLevelComment'].symbolize_keys
55
+ end
56
+
36
57
  # Returns whether YouTube API includes all attributes in this snippet.
37
58
  # For instance, YouTube API only returns tags and categoryId on
38
59
  # Videos#list, not on Videos#search. And returns position on
@@ -47,4 +68,4 @@ module Yt
47
68
  end
48
69
  end
49
70
  end
50
- end
71
+ end
@@ -37,6 +37,11 @@ module Yt
37
37
  # @return [String] the title of the channel that the video belongs to.
38
38
  delegate :channel_title, to: :snippet
39
39
 
40
+ # @return [<String>] the URL of the channel that the video belongs to.
41
+ def channel_url
42
+ "https://www.youtube.com/channel/#{channel_id}"
43
+ end
44
+
40
45
  # @!attribute [r] live_broadcast_content
41
46
  # @return [String] the type of live broadcast that the video contains.
42
47
  # Possible values are: +'live'+, +'none'+, +'upcoming'+.
@@ -226,6 +231,10 @@ module Yt
226
231
  # @return [Integer] the duration of the video (in seconds).
227
232
  delegate :duration, to: :content_detail
228
233
 
234
+ # @!attribute [r] duration
235
+ # @return [String] the length of the video as an ISO 8601 time, HH:MM:SS.
236
+ delegate :length, to: :content_detail
237
+
229
238
  # @return [Boolean] whether the video is available in 3D.
230
239
  def stereoscopic?
231
240
  content_detail.dimension == '3d'
@@ -369,6 +378,9 @@ module Yt
369
378
  delegate :concurrent_viewers, to: :live_streaming_detail
370
379
 
371
380
  ### ASSOCIATIONS ###
381
+ # @!attribute [r] comments
382
+ # @return [Yt::Collections::Comments] the video’s comments.
383
+ has_many :comment_threads
372
384
 
373
385
  # @!attribute [r] annotations
374
386
  # @return [Yt::Collections::Annotations] the video’s annotations.
@@ -376,6 +388,13 @@ module Yt
376
388
 
377
389
  has_many :resumable_sessions
378
390
 
391
+ # @!attribute [r] channel
392
+ # @return [Yt::Models::Claim, nil] the first claim on the video by
393
+ # the content owner of the video, if eagerly loaded.
394
+ def claim
395
+ @claim
396
+ end
397
+
379
398
  ### ANALYTICS ###
380
399
 
381
400
  # @macro reports
@@ -383,9 +402,6 @@ module Yt
383
402
  # @macro report_by_video_dimensions
384
403
  has_report :views, Integer
385
404
 
386
- # @macro report_by_day
387
- has_report :uniques, Integer
388
-
389
405
  # @macro report_by_video_dimensions
390
406
  has_report :estimated_minutes_watched, Integer
391
407
 
@@ -414,12 +430,6 @@ module Yt
414
430
  # @macro report_by_day_and_country
415
431
  has_report :subscribers_lost, Integer
416
432
 
417
- # @macro report_by_day_and_country
418
- has_report :favorites_added, Integer
419
-
420
- # @macro report_by_day_and_country
421
- has_report :favorites_removed, Integer
422
-
423
433
  # @macro report_by_day_and_country
424
434
  has_report :videos_added_to_playlists, Integer
425
435
 
@@ -441,11 +451,29 @@ module Yt
441
451
  # @macro report_by_day_and_state
442
452
  has_report :annotation_close_rate, Float
443
453
 
454
+ # @macro report_by_day_and_state
455
+ has_report :card_impressions, Integer
456
+
457
+ # @macro report_by_day_and_state
458
+ has_report :card_clicks, Integer
459
+
460
+ # @macro report_by_day_and_state
461
+ has_report :card_click_rate, Float
462
+
463
+ # @macro report_by_day_and_state
464
+ has_report :card_teaser_impressions, Integer
465
+
466
+ # @macro report_by_day_and_state
467
+ has_report :card_teaser_clicks, Integer
468
+
469
+ # @macro report_by_day_and_state
470
+ has_report :card_teaser_click_rate, Float
471
+
444
472
  # @macro report_by_day_and_country
445
- has_report :earnings, Float
473
+ has_report :estimated_revenue, Float
446
474
 
447
475
  # @macro report_by_day_and_country
448
- has_report :impressions, Integer
476
+ has_report :ad_impressions, Integer
449
477
 
450
478
  # @macro report_by_day_and_country
451
479
  has_report :monetized_playbacks, Integer
@@ -576,6 +604,9 @@ module Yt
576
604
  if options[:player]
577
605
  @player = Player.new data: options[:player]
578
606
  end
607
+ if options[:claim]
608
+ @claim = options[:claim]
609
+ end
579
610
  end
580
611
 
581
612
  # @private
@@ -0,0 +1,186 @@
1
+ require 'yt/models/base'
2
+
3
+ module Yt
4
+ module Models
5
+ # Provides methods to interact with YouTube Analytics video-groups.
6
+ # @see https://developers.google.com/youtube/analytics/v1/reference/groups
7
+ class VideoGroup < Base
8
+ # @private
9
+ attr_reader :id, :auth
10
+
11
+ ### GROUP INFO ###
12
+
13
+ has_one :group_info
14
+
15
+ # @!attribute [r] title
16
+ # @return [String] the title of the group.
17
+ delegate :title, to: :group_info
18
+
19
+ # @!attribute [r] item_count
20
+ # @return [Integer] the number of resources in the group.
21
+ delegate :item_count, to: :group_info
22
+
23
+ # @!attribute [r] published_at
24
+ # @return [Time] the date and time when the group was created.
25
+ delegate :published_at, to: :group_info
26
+
27
+ ### ASSOCIATIONS ###
28
+
29
+ # @!attribute [r] group_items
30
+ # @return [Yt::Collections::GroupItems] the group’s items.
31
+ has_many :group_items
32
+
33
+ ### ANALYTICS ###
34
+
35
+ # @macro reports
36
+
37
+ # @macro report_by_video_dimensions
38
+ has_report :views, Integer
39
+
40
+ # @macro report_by_video_dimensions
41
+ has_report :estimated_minutes_watched, Integer
42
+
43
+ # @macro report_by_gender_and_age_group
44
+ has_report :viewer_percentage, Float
45
+
46
+ # @macro report_by_day_and_country
47
+ has_report :comments, Integer
48
+
49
+ # @macro report_by_day_and_country
50
+ has_report :likes, Integer
51
+
52
+ # @macro report_by_day_and_country
53
+ has_report :dislikes, Integer
54
+
55
+ # @macro report_by_day_and_country
56
+ has_report :shares, Integer
57
+
58
+ # @note This is not the total number of subscribers gained by the video’s
59
+ # channel, but the subscribers gained *from* the video’s page.
60
+ # @macro report_by_day_and_country
61
+ has_report :subscribers_gained, Integer
62
+
63
+ # @note This is not the total number of subscribers lost by the video’s
64
+ # channel, but the subscribers lost *from* the video’s page.
65
+ # @macro report_by_day_and_country
66
+ has_report :subscribers_lost, Integer
67
+
68
+ # @macro report_by_day_and_country
69
+ has_report :videos_added_to_playlists, Integer
70
+
71
+ # @macro report_by_day_and_country
72
+ has_report :videos_removed_from_playlists, Integer
73
+
74
+ # @macro report_by_day_and_state
75
+ has_report :average_view_duration, Integer
76
+
77
+ # @macro report_by_day_and_state
78
+ has_report :average_view_percentage, Float
79
+
80
+ # @macro report_by_day_and_state
81
+ has_report :annotation_clicks, Integer
82
+
83
+ # @macro report_by_day_and_state
84
+ has_report :annotation_click_through_rate, Float
85
+
86
+ # @macro report_by_day_and_state
87
+ has_report :annotation_close_rate, Float
88
+
89
+ # @macro report_by_day_and_state
90
+ has_report :card_impressions, Integer
91
+
92
+ # @macro report_by_day_and_state
93
+ has_report :card_clicks, Integer
94
+
95
+ # @macro report_by_day_and_state
96
+ has_report :card_click_rate, Float
97
+
98
+ # @macro report_by_day_and_state
99
+ has_report :card_teaser_impressions, Integer
100
+
101
+ # @macro report_by_day_and_state
102
+ has_report :card_teaser_clicks, Integer
103
+
104
+ # @macro report_by_day_and_state
105
+ has_report :card_teaser_click_rate, Float
106
+
107
+ # @macro report_by_day_and_country
108
+ has_report :estimated_revenue, Float
109
+
110
+ # @macro report_by_day_and_country
111
+ has_report :ad_impressions, Integer
112
+
113
+ # @macro report_by_day_and_country
114
+ has_report :monetized_playbacks, Integer
115
+
116
+ # @macro report_by_day_and_country
117
+ has_report :playback_based_cpm, Float
118
+
119
+ ### PRIVATE API ###
120
+
121
+ # @private
122
+ def initialize(options = {})
123
+ @id = options[:id]
124
+ @auth = options[:auth]
125
+ @group_info = options[:group_info] if options[:group_info]
126
+ end
127
+
128
+ # @private
129
+ # Tells `has_reports` to retrieve group reports from the Analytics API.
130
+ def reports_params
131
+ {}.tap do |params|
132
+ if auth.owner_name
133
+ params[:ids] = "contentOwner==#{auth.owner_name}"
134
+ else
135
+ params[:ids] = "channel==mine"
136
+ end
137
+ params[:filters] = "group==#{id}"
138
+ end
139
+ end
140
+
141
+ def all_video_ids
142
+ resource_ids = group_items.map{|item| item.data['resource']['id']}.uniq
143
+ case group_info.data["itemType"]
144
+ when "youtube#video"
145
+ resource_ids
146
+ when "youtube#channel"
147
+ resource_ids.flat_map do |channel_id|
148
+ Yt::Channel.new(id: channel_id, auth: @auth).videos.map(&:id)
149
+ end
150
+ else
151
+ []
152
+ end
153
+ end
154
+
155
+ def videos
156
+ all_video_ids.each_slice(50).flat_map do |video_ids|
157
+ conditions = {id: video_ids.join(',')}
158
+ conditions[:part] = 'snippet,status,statistics,contentDetails'
159
+ Collections::Videos.new(auth: @auth).where(conditions).map(&:itself)
160
+ end
161
+ end
162
+
163
+ def all_channel_ids
164
+ resource_ids = group_items.map {|item| item.data['resource']['id']}.uniq
165
+ case group_info.data['itemType']
166
+ when "youtube#video"
167
+ resource_ids.flat_map do |video_id|
168
+ Yt::Video.new(id: video_id, auth: @auth).channel_id
169
+ end.uniq
170
+ when "youtube#channel"
171
+ resource_ids
172
+ else
173
+ []
174
+ end
175
+ end
176
+
177
+ def channels
178
+ all_channel_ids.each_slice(50).flat_map do |channel_ids|
179
+ conditions = {id: channel_ids.join(',')}
180
+ conditions[:part] = 'snippet'
181
+ Collections::Channels.new(auth: @auth).where(conditions).map(&:itself)
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end