yt 0.14.7 → 0.15.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 +4 -4
- data/CHANGELOG.md +19 -0
- data/README.md +17 -12
- data/lib/yt/associations/has_reports.rb +3 -3
- data/lib/yt/associations/has_viewer_percentages.rb +3 -9
- data/lib/yt/collections/playlist_items.rb +6 -0
- data/lib/yt/collections/reports.rb +11 -2
- data/lib/yt/collections/videos.rb +2 -2
- data/lib/yt/collections/viewer_percentages.rb +1 -0
- data/lib/yt/models/channel.rb +4 -0
- data/lib/yt/models/playlist_item.rb +15 -1
- data/lib/yt/models/snippet.rb +9 -8
- data/lib/yt/models/video.rb +5 -1
- data/lib/yt/version.rb +1 -1
- data/spec/collections/reports_spec.rb +2 -2
- data/spec/requests/as_account/account_spec.rb +2 -2
- data/spec/requests/as_account/authentications_spec.rb +7 -4
- data/spec/requests/as_account/channel_spec.rb +3 -2
- data/spec/requests/as_account/playlist_item_spec.rb +1 -1
- data/spec/requests/as_account/playlist_spec.rb +18 -2
- data/spec/requests/as_account/video_spec.rb +2 -1
- data/spec/requests/as_content_owner/channel_spec.rb +53 -4
- data/spec/requests/as_content_owner/video_spec.rb +67 -26
- data/spec/requests/as_server_app/playlist_item_spec.rb +1 -1
- data/spec/requests/as_server_app/playlist_spec.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 54209e7c3dedc665ad4d6b0d93bcf6c6d9d6f546
|
4
|
+
data.tar.gz: 6e09959e44cbf2aad7bcf29df8dfa25f6cc903c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3a83c419303aa9980ecc4769c711798742aa0a3a77202ef04e18300ba32d414994f9e2b3fa6dd5042489e5b9caaca75966c4bdcfe1a3e1a995f641d176f5a89f
|
7
|
+
data.tar.gz: 5f31bea6b6e1d473a42f73f2971efd7567220d0283c645b488ea6f35870be5e460352346996469179408f11fc9190ce61e17ce2ac435499ae89e732ead1e65b0
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,25 @@ 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.15.0 - 2015-04-19
|
10
|
+
|
11
|
+
**How to upgrade**
|
12
|
+
|
13
|
+
If your code never calls the `viewer_percentage(gender: [:female|:male])` method
|
14
|
+
on a Channel or Video object, then you are good to go.
|
15
|
+
|
16
|
+
If it does, then replace your calls to `viewer_percentage(gender: :female)`
|
17
|
+
with `viewer_percentage(by: gender)[:female]`, and do the same for `:male`.
|
18
|
+
|
19
|
+
Note that the _plural_ `viewer_percentages` method still works but it’s
|
20
|
+
deprecated: you should use `viewer_percentage` instead.
|
21
|
+
|
22
|
+
* [ENHANCEMENT] Remove `:gender` option in `viewer_percentage` in favor of a more generic `:by`
|
23
|
+
* [FEATURE] New `by: :gender` option for reports, to return viewer percentage by gender
|
24
|
+
* [FEATURE] New `by: :age_group` option for reports, to return viewer percentage by age group
|
25
|
+
* [ENHANCEMENT] The viewer percentage report now accepts start/end date options (like any other report)
|
26
|
+
* [DEPRECATION] Deprecate `viewer_percentages` in favor of `viewer_percentage`.
|
27
|
+
|
9
28
|
## 0.14.7 - 2015-04-17
|
10
29
|
|
11
30
|
* [FEATURE] New `by: :device_type` option for reports, to return views and estimated watched minutes (channels) by device
|
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.
|
44
|
+
gem 'yt', '~> 0.15.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*)
|
@@ -156,7 +156,7 @@ Use [Yt::Channel](http://rubydoc.info/github/Fullscreen/yt/master/Yt/Models/Chan
|
|
156
156
|
* retrieve the views and estimated minutes watched by video
|
157
157
|
* retrieve the views and estimated minutes watched by playlist
|
158
158
|
* retrieve the views and estimated minutes watched by device type
|
159
|
-
* retrieve the viewer percentage of a channel by gender
|
159
|
+
* retrieve the viewer percentage of a channel by gender, by age group or by both
|
160
160
|
|
161
161
|
```ruby
|
162
162
|
# Channels can be initialized with ID or URL
|
@@ -215,8 +215,7 @@ channel.favorites_removed from: '2014-08-30', to: '2014-08-31' #=> {Sat, 30 Aug
|
|
215
215
|
channel.estimated_minutes_watched #=> {Sun, 22 Feb 2015=>2433258.0, Mon, 23 Feb 2015=>2634360.0, …}
|
216
216
|
channel.average_view_duration #=> {Sun, 22 Feb 2015=>329.0, Mon, 23 Feb 2015=>326.0, …}
|
217
217
|
channel.average_view_percentage # {Sun, 22 Feb 2015=>38.858253094977265, Mon, 23 Feb 2015=>37.40014235438217, …}
|
218
|
-
channel.
|
219
|
-
channel.viewer_percentage(gender: :male) #=> 49.12
|
218
|
+
channel.viewer_percentage #=> {female: {'18-24' => 12.12, '25-34' => 16.16,…}…}
|
220
219
|
|
221
220
|
channel.views since: 7.days.ago, by: :traffic_source #=> {advertising: 10.0, related_video: 20.0, promoted: 5.0, subscriber: 1.0, channel: 3.0, other: 7.0}
|
222
221
|
channel.estimated_minutes_watched since: 7.days.ago, by: :traffic_source #=> {annotation: 10.0, external_app: 20.0, external_url: 5.0, embedded: 1.0, search: 3.0}
|
@@ -258,8 +257,8 @@ channel.subscribers_lost from: '2014-08-30', to: '2014-08-31' #=> {Sat, 30 Aug 2
|
|
258
257
|
channel.estimated_minutes_watched #=> {Sun, 22 Feb 2015=>2433258.0, Mon, 23 Feb 2015=>2634360.0, …}
|
259
258
|
channel.average_view_duration #=> {Sun, 22 Feb 2015=>329.0, Mon, 23 Feb 2015=>326.0, …}
|
260
259
|
channel.average_view_percentage # {Sun, 22 Feb 2015=>38.858253094977265, Mon, 23 Feb 2015=>37.40014235438217, …}
|
261
|
-
channel.
|
262
|
-
|
260
|
+
channel.viewer_percentage since: 7.days.ago #=> {female: {'18-24' => 12.12, '25-34' => 16.16,…}…}
|
261
|
+
|
263
262
|
channel.views since: 7.days.ago, by: :traffic_source #=> {advertising: 10.0, related_video: 20.0, promoted: 5.0, subscriber: 1.0, channel: 3.0, other: 7.0}
|
264
263
|
channel.estimated_minutes_watched since: 7.days.ago, by: :traffic_source #=> {annotation: 10.0, external_app: 20.0, external_url: 5.0, embedded: 1.0, search: 3.0}
|
265
264
|
channel.views since: 7.days.ago, by: :playback_location #=> {embedded: 34.0, watch: 467.0, channel: 462.0, other: 3.0}
|
@@ -275,6 +274,8 @@ channel.estimated_minutes_watched since: 7.days.ago, by: :playlist #=> {#<Yt::Mo
|
|
275
274
|
channel.views since: 7.days.ago, by: :device_type #=> {mobile: 144473.0, unknown_platform: 840.0, game_console: 4940.0, desktop: 102889.0, tv: 4134.0, tablet: 50189.0}
|
276
275
|
channel.estimated_minutes_watched since: 7.days.ago, by: :device_type #=> {mobile: 144473.0, unknown_platform: 840.0, game_console: 4940.0, desktop: 102889.0, tv: 4134.0, tablet: 50189.0}
|
277
276
|
channel.monetized_playbacks_on 5.days.ago #=> 123.0
|
277
|
+
channel.viewer_percentage since: 7.days.ago, by: :gender #=> {female: 49.12, male: 50.88}
|
278
|
+
channel.viewer_percentage since: 7.days.ago, by: :age_group #=> {'18-24' => 12.12, '25-34' => 16.16,…}
|
278
279
|
|
279
280
|
channel.content_owner #=> 'CMSname'
|
280
281
|
channel.linked_at #=> Wed, 28 May 2014
|
@@ -299,7 +300,7 @@ Use [Yt::Video](http://rubydoc.info/github/Fullscreen/yt/master/Yt/Models/Video)
|
|
299
300
|
* retrieve the views of a video by embedded player location
|
300
301
|
* retrieve the views of a video by related video
|
301
302
|
* retrieve the views of a video by device type
|
302
|
-
* retrieve the viewer percentage of a video by gender
|
303
|
+
* retrieve the viewer percentage of a video by gender, by age group or by both
|
303
304
|
* retrieve data about live-streaming videos
|
304
305
|
* retrieve the advertising options of a video
|
305
306
|
|
@@ -396,14 +397,15 @@ video.favorites_removed from: '2014-08-30', to: '2014-08-31' #=> {Sat, 30 Aug 20
|
|
396
397
|
video.average_view_duration #=> {Sun, 22 Feb 2015=>329.0, Mon, 23 Feb 2015=>326.0, …}
|
397
398
|
video.average_view_percentage # {Sun, 22 Feb 2015=>38.858253094977265, Mon, 23 Feb 2015=>37.40014235438217, …}
|
398
399
|
video.estimated_minutes_watched #=> {Sun, 22 Feb 2015=>2433258.0, Mon, 23 Feb 2015=>2634360.0, …}
|
399
|
-
video.
|
400
|
-
video.viewer_percentage(gender: :female) #=> 49.12
|
400
|
+
video.viewer_percentage #=> {female: {'18-24' => 12.12, '25-34' => 16.16,…}…}
|
401
401
|
|
402
402
|
video.views since: 7.days.ago, by: :traffic_source #=> {advertising: 10.0, related_video: 20.0, promoted: 5.0, subscriber: 1.0, channel: 3.0, other: 7.0}
|
403
403
|
video.views since: 7.days.ago, by: :playback_location #=> {:embedded=>6.0, :watch=>11.0}
|
404
404
|
video.views since: 7.days.ago, by: :embedded_player_location #=> {"fullscreen.net"=>45.0, "linkedin.com"=>5.0, "mashable.com"=>1.0, "unknown"=>1.0}
|
405
405
|
video.views since: 7.days.ago, by: :related_video #=> {#<Yt::Models::Video @id=...>: 10.0, #<Yt::Models::Video @id=...>: 20.0, …}
|
406
406
|
video.views since: 7.days.ago, by: :device_type #=> {mobile: 144473.0, unknown_platform: 840.0, game_console: 4940.0, desktop: 102889.0, tv: 4134.0, tablet: 50189.0}
|
407
|
+
video.viewer_percentage since: 7.days.ago, by: :gender #=> {female: 49.12, male: 50.88}
|
408
|
+
video.viewer_percentage since: 7.days.ago, by: :age_group #=> {'18-24' => 12.12, '25-34' => 16.16,…}
|
407
409
|
|
408
410
|
video.delete #=> true
|
409
411
|
```
|
@@ -429,12 +431,15 @@ video.average_view_percentage # {Sun, 22 Feb 2015=>38.858253094977265, Mon, 23 F
|
|
429
431
|
video.estimated_minutes_watched #=> {Sun, 22 Feb 2015=>2433258.0, Mon, 23 Feb 2015=>2634360.0, …}
|
430
432
|
video.impressions_on 5.days.ago #=> 157.0
|
431
433
|
video.monetized_playbacks_on 5.days.ago #=> 123.0
|
432
|
-
|
433
|
-
video.viewer_percentages #=> {female: {'18-24' => 12.12, '25-34' => 16.16,…}…}
|
434
|
-
video.viewer_percentage(gender: :female) #=> 49.12
|
434
|
+
video.viewer_percentage #=> {female: {'18-24' => 12.12, '25-34' => 16.16,…}…}
|
435
435
|
|
436
436
|
video.views since: 7.days.ago, by: :traffic_source #=> {advertising: 10.0, related_video: 20.0, promoted: 5.0, subscriber: 1.0, channel: 3.0, other: 7.0}
|
437
437
|
video.views since: 7.days.ago, by: :playback_location #=> {:embedded=>6.0, :watch=>11.0}
|
438
|
+
video.views since: 7.days.ago, by: :embedded_player_location #=> {"fullscreen.net"=>45.0, "linkedin.com"=>5.0, "mashable.com"=>1.0, "unknown"=>1.0}
|
439
|
+
video.views since: 7.days.ago, by: :related_video #=> {#<Yt::Models::Video @id=...>: 10.0, #<Yt::Models::Video @id=...>: 20.0, …}
|
440
|
+
video.views since: 7.days.ago, by: :device_type #=> {mobile: 144473.0, unknown_platform: 840.0, game_console: 4940.0, desktop: 102889.0, tv: 4134.0, tablet: 50189.0}
|
441
|
+
video.viewer_percentage since: 7.days.ago, by: :gender #=> {female: 49.12, male: 50.88}
|
442
|
+
video.viewer_percentage since: 7.days.ago, by: :age_group #=> {'18-24' => 12.12, '25-34' => 16.16,…}
|
438
443
|
|
439
444
|
video.ad_formats #=> ["standard_instream", "trueview_instream"]
|
440
445
|
```
|
@@ -43,10 +43,10 @@ module Yt
|
|
43
43
|
|
44
44
|
def define_metric_method(metric)
|
45
45
|
define_method metric do |options = {}|
|
46
|
-
from = options[:since] || options[:from] || 5.days.ago
|
47
|
-
to = options[:until] || options[:to] || 1.day.ago
|
46
|
+
from = options[:since] || options[:from] || (metric == :viewer_percentage ? 3.months.ago : 5.days.ago)
|
47
|
+
to = options[:until] || options[:to] || (metric == :viewer_percentage ? Date.today : 1.day.ago)
|
48
48
|
range = Range.new *[from, to].map(&:to_date)
|
49
|
-
dimension = options[:by] || :day
|
49
|
+
dimension = options[:by] || (metric == :viewer_percentage ? :gender_age_group : :day)
|
50
50
|
|
51
51
|
ivar = instance_variable_get "@#{metric}_#{dimension}"
|
52
52
|
instance_variable_set "@#{metric}_#{dimension}", ivar || {}
|
@@ -4,8 +4,10 @@ module Yt
|
|
4
4
|
#
|
5
5
|
# YouTube resources with viewer percentage reports are:
|
6
6
|
# {Yt::Models::Channel channels} and {Yt::Models::Channel videos}.
|
7
|
+
# @deprecated Use {#viewer_percentage} instead.
|
7
8
|
module HasViewerPercentages
|
8
9
|
# @!macro has_viewer_percentages
|
10
|
+
# @!deprecated Use {#viewer_percentage} instead.
|
9
11
|
# @!method viewer_percentages
|
10
12
|
# @return [Hash<Symbol,Hash<String,Float>>] the viewer percentages.
|
11
13
|
# The first-level hash identifies the genres (:female, :male).
|
@@ -20,7 +22,7 @@ module Yt
|
|
20
22
|
# @example Return the % of male viewers of a video
|
21
23
|
# channel.viewer_percentage(gender: :male) #=> 52.02
|
22
24
|
|
23
|
-
# Defines
|
25
|
+
# Defines one public instance methods to access the viewer percentages of
|
24
26
|
# a resource for a specific metric.
|
25
27
|
# @example Adds +viewer_percentages+ and +viewer_percentage+ on Channel.
|
26
28
|
# class Channel < Resource
|
@@ -30,23 +32,15 @@ module Yt
|
|
30
32
|
require 'yt/collections/viewer_percentages'
|
31
33
|
|
32
34
|
define_viewer_percentages_method
|
33
|
-
define_viewer_percentage_method
|
34
35
|
end
|
35
36
|
|
36
37
|
private
|
37
38
|
|
38
39
|
def define_viewer_percentages_method
|
39
|
-
# @todo: add options like start and end date
|
40
40
|
define_method :viewer_percentages do
|
41
41
|
@viewer_percentages ||= Collections::ViewerPercentages.of(self)[id]
|
42
42
|
end
|
43
43
|
end
|
44
|
-
|
45
|
-
def define_viewer_percentage_method
|
46
|
-
define_method :viewer_percentage do |filters = {}|
|
47
|
-
viewer_percentages[filters[:gender]].values.sum.round(2)
|
48
|
-
end
|
49
|
-
end
|
50
44
|
end
|
51
45
|
end
|
52
46
|
end
|
@@ -13,6 +13,12 @@ module Yt
|
|
13
13
|
|
14
14
|
private
|
15
15
|
|
16
|
+
def attributes_for_new_item(data)
|
17
|
+
snippet = data.fetch 'snippet', {}
|
18
|
+
data['snippet'].reverse_merge! complete: snippet.key?('position')
|
19
|
+
super(data)
|
20
|
+
end
|
21
|
+
|
16
22
|
# @return [Hash] the parameters to submit to YouTube to list playlist items.
|
17
23
|
# @see https://developers.google.com/youtube/v3/docs/playlistItems/list
|
18
24
|
def list_params
|
@@ -11,6 +11,9 @@ module Yt
|
|
11
11
|
hash[:video] = {name: 'video', parse: ->(video_id) { Yt::Video.new id: video_id, auth: @auth } }
|
12
12
|
hash[:playlist] = {name: 'playlist', parse: ->(playlist_id) { Yt::Playlist.new id: playlist_id, auth: @auth } }
|
13
13
|
hash[:device_type] = {name: 'deviceType', parse: ->(type) { type.downcase.to_sym } }
|
14
|
+
hash[:gender_age_group] = {name: 'gender,ageGroup', parse: ->(gender) { gender.downcase.to_sym }}
|
15
|
+
hash[:gender] = {name: 'gender', parse: ->(gender) { gender.downcase.to_sym } }
|
16
|
+
hash[:age_group] = {name: 'ageGroup', parse: ->(age_group) { age_group[3..-1] } }
|
14
17
|
end
|
15
18
|
|
16
19
|
# @see https://developers.google.com/youtube/analytics/v1/dimsmets/dims#Traffic_Source_Dimensions
|
@@ -46,7 +49,13 @@ module Yt
|
|
46
49
|
def within(days_range, dimension, try_again = true)
|
47
50
|
@days_range = days_range
|
48
51
|
@dimension = dimension
|
49
|
-
|
52
|
+
if dimension == :gender_age_group # array of array
|
53
|
+
Hash.new{|h,k| h[k] = Hash.new 0.0}.tap do |hash|
|
54
|
+
each{|gender, age_group, value| hash[gender][age_group[3..-1]] = value}
|
55
|
+
end
|
56
|
+
else
|
57
|
+
Hash[*flat_map{|value| [value.first, value.last]}]
|
58
|
+
end
|
50
59
|
# NOTE: Once in a while, YouTube responds with 400 Error and the message
|
51
60
|
# "Invalid query. Query did not conform to the expectations."; in this
|
52
61
|
# case running the same query after one second fixes the issue. This is
|
@@ -60,7 +69,7 @@ module Yt
|
|
60
69
|
private
|
61
70
|
|
62
71
|
def new_item(data)
|
63
|
-
[instance_exec(data.first, &DIMENSIONS[@dimension][:parse]), data
|
72
|
+
[instance_exec(data.first, &DIMENSIONS[@dimension][:parse]), *data[1..-1]]
|
64
73
|
end
|
65
74
|
|
66
75
|
# @see https://developers.google.com/youtube/analytics/v1/content_owner_reports
|
@@ -17,7 +17,7 @@ module Yt
|
|
17
17
|
|
18
18
|
def attributes_for_new_item(data)
|
19
19
|
id = use_list_endpoint? ? data['id'] : data['id']['videoId']
|
20
|
-
snippet = data['snippet'].reverse_merge
|
20
|
+
snippet = data['snippet'].reverse_merge complete: false if data['snippet']
|
21
21
|
{}.tap do |attributes|
|
22
22
|
attributes[:id] = id
|
23
23
|
attributes[:snippet] = snippet
|
@@ -39,7 +39,7 @@ module Yt
|
|
39
39
|
video = videos.find{|v| v.id == item['id']['videoId']}
|
40
40
|
parts.each do |part|
|
41
41
|
item[part] = case part
|
42
|
-
when 'snippet' then video.snippet.data.merge
|
42
|
+
when 'snippet' then video.snippet.data.merge complete: true
|
43
43
|
when 'status' then video.status.data
|
44
44
|
when 'statistics' then video.statistics_set.data
|
45
45
|
when 'contentDetails' then video.content_detail.data
|
data/lib/yt/models/channel.rb
CHANGED
@@ -5,7 +5,7 @@ module Yt
|
|
5
5
|
# Provides methods to interact with YouTube playlist items.
|
6
6
|
# @see https://developers.google.com/youtube/v3/docs/playlistItems
|
7
7
|
class PlaylistItem < Resource
|
8
|
-
delegate :channel_id, :channel_title, :playlist_id, :
|
8
|
+
delegate :channel_id, :channel_title, :playlist_id, :video_id,
|
9
9
|
:video, to: :snippet
|
10
10
|
|
11
11
|
def delete(options = {})
|
@@ -17,6 +17,20 @@ module Yt
|
|
17
17
|
!@id.nil?
|
18
18
|
end
|
19
19
|
|
20
|
+
# Returns the position of the item in the playlist.
|
21
|
+
# Since YouTube API does not return the position on PlaylistItem#create,
|
22
|
+
# the memoized @snippet is erased if the video was instantiated like that,
|
23
|
+
# so that the full snippet (with position) is loaded, rather than the
|
24
|
+
# partial one.
|
25
|
+
# @see https://developers.google.com/youtube/v3/docs/playlistItems
|
26
|
+
# @return [Integer] the order in which the item appears in a playlist.
|
27
|
+
def position
|
28
|
+
unless snippet.position || snippet.complete? || @auth.nil?
|
29
|
+
@snippet = nil
|
30
|
+
end
|
31
|
+
snippet.position
|
32
|
+
end
|
33
|
+
|
20
34
|
private
|
21
35
|
|
22
36
|
def resource_id
|
data/lib/yt/models/snippet.rb
CHANGED
@@ -146,16 +146,17 @@ module Yt
|
|
146
146
|
@video ||= Video.new id: video_id, auth: @auth if video_id
|
147
147
|
end
|
148
148
|
|
149
|
-
# Returns whether YouTube API includes
|
150
|
-
# YouTube API only returns tags on Videos#list, not on
|
149
|
+
# Returns whether YouTube API includes all attributes in this snippet.
|
150
|
+
# For instance, YouTube API only returns tags on Videos#list, not on
|
151
|
+
# Videos#search. And returns position on PlaylistItems#list, not on
|
152
|
+
# PlaylistItems#insert.
|
151
153
|
# This method is used to guarantee that, when a video was instantiated
|
152
|
-
# by
|
153
|
-
#
|
154
|
-
# made to retrieve the correct tags.
|
154
|
+
# by one of the methods above, an additional call to is made to retrieve
|
155
|
+
# the full snippet in case an attribute is missing.
|
155
156
|
# @see https://developers.google.com/youtube/v3/docs/videos
|
156
|
-
# @return [Boolean] whether YouTube API includes
|
157
|
-
def
|
158
|
-
@
|
157
|
+
# @return [Boolean] whether YouTube API includes the complete snippet.
|
158
|
+
def complete?
|
159
|
+
@complete ||= data.fetch :complete, true
|
159
160
|
end
|
160
161
|
|
161
162
|
private
|
data/lib/yt/models/video.rb
CHANGED
@@ -89,6 +89,10 @@ module Yt
|
|
89
89
|
# @macro has_report
|
90
90
|
has_report :monetized_playbacks
|
91
91
|
|
92
|
+
# @macro has_report
|
93
|
+
has_report :viewer_percentage
|
94
|
+
|
95
|
+
# @deprecated Use {#has_report :viewer_percentage}.
|
92
96
|
# @macro has_viewer_percentages
|
93
97
|
has_viewer_percentages
|
94
98
|
|
@@ -124,7 +128,7 @@ module Yt
|
|
124
128
|
# @return [Array<Yt::Models::Tag>] the list of keyword tags associated
|
125
129
|
# with the video.
|
126
130
|
def tags
|
127
|
-
unless snippet.tags.any? || snippet.
|
131
|
+
unless snippet.tags.any? || snippet.complete? || @auth.nil?
|
128
132
|
@snippet = nil
|
129
133
|
end
|
130
134
|
snippet.tags
|
data/lib/yt/version.rb
CHANGED
@@ -9,7 +9,7 @@ describe Yt::Collections::Reports do
|
|
9
9
|
let(:msg) { {response_body: {error: {errors: [error]}}}.to_json }
|
10
10
|
|
11
11
|
describe '#within' do
|
12
|
-
let(:result) { reports.within Range.new(5.days.ago, 4.days.ago) }
|
12
|
+
let(:result) { reports.within Range.new(5.days.ago, 4.days.ago), :day }
|
13
13
|
context 'given the request raises error 400 with "Invalid Query" message' do
|
14
14
|
let(:reason) { 'badRequest' }
|
15
15
|
let(:message) { 'Invalid query. Query did not conform to the expectations' }
|
@@ -22,7 +22,7 @@ describe Yt::Collections::Reports do
|
|
22
22
|
end
|
23
23
|
|
24
24
|
context 'but returns a success code 2XX the second time' do
|
25
|
-
before { try_again.and_return [1,2] }
|
25
|
+
before { try_again.and_return [[1,2]] }
|
26
26
|
it { expect{result}.not_to fail }
|
27
27
|
end
|
28
28
|
end
|
@@ -51,12 +51,12 @@ describe Yt::Account, :device_app do
|
|
51
51
|
end
|
52
52
|
|
53
53
|
describe '.includes(:snippet)' do
|
54
|
-
let(:video) { $account.videos.
|
54
|
+
let(:video) { $account.videos.first }
|
55
55
|
|
56
56
|
specify 'eager-loads the *full* snippet of each video' do
|
57
57
|
expect(video.instance_variable_defined? :@snippet).to be true
|
58
58
|
expect(video.channel_title).to be
|
59
|
-
expect(video.snippet
|
59
|
+
expect(video.snippet).to be_complete
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -109,10 +109,13 @@ describe Yt::Account, :device_app do
|
|
109
109
|
it { expect{account.authentication}.to raise_error Yt::Errors::MissingAuth }
|
110
110
|
end
|
111
111
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
112
|
+
# NOTE: This test is commented out because of YouTube irrational behavior
|
113
|
+
# of using to return "MissingAuth" when passing a wrong device code, and
|
114
|
+
# now randomly returning `{"error"=>"internal_failure"}` instead.
|
115
|
+
# context 'and an invalid device code' do
|
116
|
+
# before { attrs[:device_code] = '--not-a-valid-device-code--' }
|
117
|
+
# it { expect{account.authentication}.to raise_error Yt::Errors::MissingAuth }
|
118
|
+
# end
|
116
119
|
end
|
117
120
|
|
118
121
|
context 'given no token or code' do
|
@@ -26,7 +26,7 @@ describe Yt::Channel, :device_app do
|
|
26
26
|
|
27
27
|
specify 'returns the videos in the channel without their tags' do
|
28
28
|
expect(video).to be_a Yt::Video
|
29
|
-
expect(video.snippet
|
29
|
+
expect(video.snippet).not_to be_complete
|
30
30
|
end
|
31
31
|
|
32
32
|
describe '.where(id: *anything*)' do
|
@@ -175,6 +175,7 @@ describe Yt::Channel, :device_app do
|
|
175
175
|
expect{channel.estimated_minutes_watched}.not_to raise_error
|
176
176
|
expect{channel.average_view_duration}.not_to raise_error
|
177
177
|
expect{channel.average_view_percentage}.not_to raise_error
|
178
|
+
expect{channel.viewer_percentage}.not_to raise_error
|
178
179
|
expect{channel.earnings}.to raise_error Yt::Errors::Unauthorized
|
179
180
|
expect{channel.impressions}.to raise_error Yt::Errors::Unauthorized
|
180
181
|
expect{channel.monetized_playbacks}.to raise_error Yt::Errors::Unauthorized
|
@@ -195,9 +196,9 @@ describe Yt::Channel, :device_app do
|
|
195
196
|
expect{channel.impressions_on 3.days.ago}.to raise_error Yt::Errors::Unauthorized
|
196
197
|
end
|
197
198
|
|
199
|
+
# @deprecated, use channel.viewer_percentage instead
|
198
200
|
it 'returns valid reports for channel-related demographics' do
|
199
201
|
expect{channel.viewer_percentages}.not_to raise_error
|
200
|
-
expect{channel.viewer_percentage}.not_to raise_error
|
201
202
|
end
|
202
203
|
|
203
204
|
it 'cannot give information about its content owner' do
|
@@ -5,7 +5,7 @@ describe Yt::PlaylistItem, :device_app do
|
|
5
5
|
subject(:item) { Yt::PlaylistItem.new id: id, auth: $account }
|
6
6
|
|
7
7
|
context 'given an existing playlist item' do
|
8
|
-
let(:id) { '
|
8
|
+
let(:id) { 'PLjW_GNR5Ir0GMlbJzA-aW0UV8TchJFb8p3uzrLNcZKPY' }
|
9
9
|
|
10
10
|
it 'returns valid metadata' do
|
11
11
|
expect(item.title).to be_a String
|
@@ -7,7 +7,7 @@ describe Yt::Playlist, :device_app do
|
|
7
7
|
subject(:playlist) { Yt::Playlist.new id: id, auth: $account }
|
8
8
|
|
9
9
|
context 'given an existing playlist' do
|
10
|
-
let(:id) { '
|
10
|
+
let(:id) { 'PLSWYkYzOrPMT9pJG5St5G0WDalhRzGkU4' }
|
11
11
|
|
12
12
|
it 'returns valid metadata' do
|
13
13
|
expect(playlist.title).to be_a String
|
@@ -21,6 +21,8 @@ describe Yt::Playlist, :device_app do
|
|
21
21
|
end
|
22
22
|
|
23
23
|
it { expect(playlist.playlist_items.first).to be_a Yt::PlaylistItem }
|
24
|
+
it { expect(playlist.playlist_items.first.snippet).to be_complete }
|
25
|
+
it { expect(playlist.playlist_items.first.position).not_to be_nil }
|
24
26
|
end
|
25
27
|
|
26
28
|
context 'given an unknown playlist' do
|
@@ -31,7 +33,7 @@ describe Yt::Playlist, :device_app do
|
|
31
33
|
end
|
32
34
|
|
33
35
|
context 'given someone else’s playlist' do
|
34
|
-
let(:id) { '
|
36
|
+
let(:id) { 'PLSWYkYzOrPMT9pJG5St5G0WDalhRzGkU4' }
|
35
37
|
let(:video_id) { 'MESycYJytkU' }
|
36
38
|
|
37
39
|
it { expect{playlist.delete}.to fail.with 'forbidden' }
|
@@ -137,6 +139,20 @@ describe Yt::Playlist, :device_app do
|
|
137
139
|
it { expect(playlist.add_video(video_id, position: 0).position).to be 0 }
|
138
140
|
end
|
139
141
|
|
142
|
+
# NOTE: This test sounds redundant, but it’s actually a reflection of
|
143
|
+
# another irrational behavior of YouTube API. In short, if you add a new
|
144
|
+
# video to a playlist, the returned item does not have the "position"
|
145
|
+
# information. You need an extra call to get it. When YouTube fixes this
|
146
|
+
# behavior, this test (and related code) will go away.
|
147
|
+
describe 'adding the video' do
|
148
|
+
let(:item) { playlist.add_video video_id }
|
149
|
+
|
150
|
+
specify 'returns an item without its position' do
|
151
|
+
expect(item.snippet).not_to be_complete
|
152
|
+
expect(item.position).not_to be_nil # after reloading
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
140
156
|
describe 'can be removed' do
|
141
157
|
before { playlist.add_video video_id }
|
142
158
|
|
@@ -292,6 +292,7 @@ describe Yt::Video, :device_app do
|
|
292
292
|
expect{video.estimated_minutes_watched}.not_to raise_error
|
293
293
|
expect{video.average_view_duration}.not_to raise_error
|
294
294
|
expect{video.average_view_percentage}.not_to raise_error
|
295
|
+
expect{video.viewer_percentage}.not_to raise_error
|
295
296
|
expect{video.earnings}.to raise_error Yt::Errors::Unauthorized
|
296
297
|
expect{video.impressions}.to raise_error Yt::Errors::Unauthorized
|
297
298
|
expect{video.monetized_playbacks}.to raise_error Yt::Errors::Unauthorized
|
@@ -313,9 +314,9 @@ describe Yt::Video, :device_app do
|
|
313
314
|
expect{video.impressions_on 3.days.ago}.to raise_error Yt::Errors::Unauthorized
|
314
315
|
end
|
315
316
|
|
317
|
+
# @deprecated, use video.viewer_percentage instead
|
316
318
|
it 'returns valid reports for video-related demographics' do
|
317
319
|
expect{video.viewer_percentages}.not_to raise_error
|
318
|
-
expect{video.viewer_percentage}.not_to raise_error
|
319
320
|
end
|
320
321
|
end
|
321
322
|
|
@@ -311,7 +311,7 @@ describe Yt::Channel, :partner do
|
|
311
311
|
|
312
312
|
describe 'shares can be retrieved for a specific day' do
|
313
313
|
context 'in which the channel was partnered' do
|
314
|
-
let(:shares) { channel.shares_on
|
314
|
+
let(:shares) { channel.shares_on ENV['YT_TEST_PARTNER_VIDEO_DATE']}
|
315
315
|
it { expect(shares).to be_a Float }
|
316
316
|
end
|
317
317
|
|
@@ -845,6 +845,58 @@ describe Yt::Channel, :partner do
|
|
845
845
|
end
|
846
846
|
end
|
847
847
|
|
848
|
+
describe 'viewer percentage can be retrieved for a range of days' do
|
849
|
+
let(:viewer_percentage) { channel.viewer_percentage since: 1.year.ago, until: 10.days.ago}
|
850
|
+
it { expect(viewer_percentage).to be_a Hash }
|
851
|
+
end
|
852
|
+
|
853
|
+
describe 'viewer_percentage can be grouped by gender and age group' do
|
854
|
+
let(:range) { {since: 1.year.ago.to_date, until: 1.week.ago.to_date} }
|
855
|
+
let(:keys) { range.values }
|
856
|
+
|
857
|
+
specify 'without a :by option (default)' do
|
858
|
+
viewer_percentage = channel.viewer_percentage range
|
859
|
+
expect(viewer_percentage.keys).to match_array [:female, :male]
|
860
|
+
expect(viewer_percentage[:female].keys - %w(65- 35-44 45-54 13-17 25-34 55-64 18-24)).to be_empty
|
861
|
+
expect(viewer_percentage[:female].values).to all(be_instance_of Float)
|
862
|
+
expect(viewer_percentage[:male].keys - %w(65- 35-44 45-54 13-17 25-34 55-64 18-24)).to be_empty
|
863
|
+
expect(viewer_percentage[:male].values).to all(be_instance_of Float)
|
864
|
+
end
|
865
|
+
|
866
|
+
specify 'with the :by option set to :gender_age_group' do
|
867
|
+
viewer_percentage = channel.viewer_percentage range.merge by: :gender_age_group
|
868
|
+
expect(viewer_percentage.keys).to match_array [:female, :male]
|
869
|
+
expect(viewer_percentage[:female].keys - %w(65- 35-44 45-54 13-17 25-34 55-64 18-24)).to be_empty
|
870
|
+
expect(viewer_percentage[:female].values).to all(be_instance_of Float)
|
871
|
+
expect(viewer_percentage[:male].keys - %w(65- 35-44 45-54 13-17 25-34 55-64 18-24)).to be_empty
|
872
|
+
expect(viewer_percentage[:male].values).to all(be_instance_of Float)
|
873
|
+
end
|
874
|
+
end
|
875
|
+
|
876
|
+
describe 'viewer_percentage can be grouped by gender' do
|
877
|
+
let(:range) { {since: 1.year.ago.to_date, until: 1.week.ago.to_date} }
|
878
|
+
let(:keys) { range.values }
|
879
|
+
|
880
|
+
specify 'with the :by option set to :gender' do
|
881
|
+
viewer_percentage = channel.viewer_percentage range.merge by: :gender
|
882
|
+
expect(viewer_percentage.keys).to match_array [:female, :male]
|
883
|
+
expect(viewer_percentage[:female]).to be_a Float
|
884
|
+
expect(viewer_percentage[:male]).to be_a Float
|
885
|
+
end
|
886
|
+
end
|
887
|
+
|
888
|
+
describe 'viewer_percentage can be grouped by age group' do
|
889
|
+
let(:range) { {since: 1.year.ago.to_date, until: 1.week.ago.to_date} }
|
890
|
+
let(:keys) { range.values }
|
891
|
+
|
892
|
+
specify 'with the :by option set to :age_group' do
|
893
|
+
viewer_percentage = channel.viewer_percentage range.merge by: :age_group
|
894
|
+
expect(viewer_percentage.keys - %w(65- 35-44 45-54 13-17 25-34 55-64 18-24)).to be_empty
|
895
|
+
expect(viewer_percentage.values).to all(be_instance_of Float)
|
896
|
+
end
|
897
|
+
end
|
898
|
+
|
899
|
+
# @deprecated, use channel.viewer_percentage instead
|
848
900
|
specify 'viewer percentages by gender and age range can be retrieved' do
|
849
901
|
expect(channel.viewer_percentages[:female]['18-24']).to be_a Float
|
850
902
|
expect(channel.viewer_percentages[:female]['25-34']).to be_a Float
|
@@ -858,9 +910,6 @@ describe Yt::Channel, :partner do
|
|
858
910
|
expect(channel.viewer_percentages[:male]['45-54']).to be_a Float
|
859
911
|
expect(channel.viewer_percentages[:male]['55-64']).to be_a Float
|
860
912
|
expect(channel.viewer_percentages[:male]['65-']).to be_a Float
|
861
|
-
|
862
|
-
expect(channel.viewer_percentage(gender: :male)).to be_a Float
|
863
|
-
expect(channel.viewer_percentage(gender: :female)).to be_a Float
|
864
913
|
end
|
865
914
|
|
866
915
|
specify 'information about its content owner can be retrieved' do
|
@@ -15,7 +15,7 @@ describe Yt::Video, :partner do
|
|
15
15
|
|
16
16
|
describe 'earnings can be retrieved for a specific day' do
|
17
17
|
context 'in which the video made any money' do
|
18
|
-
let(:earnings) {video.earnings_on
|
18
|
+
let(:earnings) {video.earnings_on ENV['YT_TEST_PARTNER_VIDEO_DATE']}
|
19
19
|
it { expect(earnings).to be_a Float }
|
20
20
|
end
|
21
21
|
|
@@ -26,22 +26,14 @@ describe Yt::Video, :partner do
|
|
26
26
|
end
|
27
27
|
|
28
28
|
describe 'earnings can be retrieved for a range of days' do
|
29
|
-
let(:date) {
|
30
|
-
|
31
|
-
specify 'with a given start (:since option)' do
|
32
|
-
expect(video.earnings(since: date).keys.min).to eq date.to_date
|
33
|
-
end
|
29
|
+
let(:date) { ENV['YT_TEST_PARTNER_VIDEO_DATE'] }
|
34
30
|
|
35
|
-
specify 'with a given end (:until option)' do
|
36
|
-
expect(video.earnings(until: date).keys.
|
37
|
-
end
|
38
|
-
|
39
|
-
specify 'with a given start (:from option)' do
|
40
|
-
expect(video.earnings(from: date).keys.min).to eq date.to_date
|
31
|
+
specify 'with a given start and end (:since / :until option)' do
|
32
|
+
expect(video.earnings(since: date, until: date).keys.min).to eq date.to_date
|
41
33
|
end
|
42
34
|
|
43
|
-
specify 'with a given end (:to option)' do
|
44
|
-
expect(video.earnings(to: date).keys.
|
35
|
+
specify 'with a given start and end (:from / :to option)' do
|
36
|
+
expect(video.earnings(from: date, to: date).keys.min).to eq date.to_date
|
45
37
|
end
|
46
38
|
end
|
47
39
|
|
@@ -113,7 +105,7 @@ describe Yt::Video, :partner do
|
|
113
105
|
end
|
114
106
|
|
115
107
|
describe 'views can be grouped by embedded player location' do
|
116
|
-
let(:range) { {since:
|
108
|
+
let(:range) { {since: ENV['YT_TEST_PARTNER_VIDEO_DATE'], until: 3.days.ago} }
|
117
109
|
|
118
110
|
specify 'with the :by option set to :embedded_player_location' do
|
119
111
|
views = video.views range.merge by: :embedded_player_location
|
@@ -142,7 +134,7 @@ describe Yt::Video, :partner do
|
|
142
134
|
|
143
135
|
describe 'comments can be retrieved for a specific day' do
|
144
136
|
context 'in which the video was partnered' do
|
145
|
-
let(:comments) { video.comments_on
|
137
|
+
let(:comments) { video.comments_on ENV['YT_TEST_PARTNER_VIDEO_DATE']}
|
146
138
|
it { expect(comments).to be_a Float }
|
147
139
|
end
|
148
140
|
|
@@ -189,7 +181,7 @@ describe Yt::Video, :partner do
|
|
189
181
|
|
190
182
|
describe 'likes can be retrieved for a specific day' do
|
191
183
|
context 'in which the video was partnered' do
|
192
|
-
let(:likes) { video.likes_on
|
184
|
+
let(:likes) { video.likes_on ENV['YT_TEST_PARTNER_VIDEO_DATE']}
|
193
185
|
it { expect(likes).to be_a Float }
|
194
186
|
end
|
195
187
|
|
@@ -236,7 +228,7 @@ describe Yt::Video, :partner do
|
|
236
228
|
|
237
229
|
describe 'dislikes can be retrieved for a specific day' do
|
238
230
|
context 'in which the video was partnered' do
|
239
|
-
let(:dislikes) { video.dislikes_on
|
231
|
+
let(:dislikes) { video.dislikes_on ENV['YT_TEST_PARTNER_VIDEO_DATE']}
|
240
232
|
it { expect(dislikes).to be_a Float }
|
241
233
|
end
|
242
234
|
|
@@ -283,7 +275,7 @@ describe Yt::Video, :partner do
|
|
283
275
|
|
284
276
|
describe 'shares can be retrieved for a specific day' do
|
285
277
|
context 'in which the video was partnered' do
|
286
|
-
let(:shares) { video.shares_on
|
278
|
+
let(:shares) { video.shares_on ENV['YT_TEST_PARTNER_VIDEO_DATE']}
|
287
279
|
it { expect(shares).to be_a Float }
|
288
280
|
end
|
289
281
|
|
@@ -330,7 +322,7 @@ describe Yt::Video, :partner do
|
|
330
322
|
|
331
323
|
describe 'gained subscribers can be retrieved for a specific day' do
|
332
324
|
context 'in which the video was partnered' do
|
333
|
-
let(:subscribers_gained) { video.subscribers_gained_on
|
325
|
+
let(:subscribers_gained) { video.subscribers_gained_on ENV['YT_TEST_PARTNER_VIDEO_DATE']}
|
334
326
|
it { expect(subscribers_gained).to be_a Float }
|
335
327
|
end
|
336
328
|
|
@@ -377,7 +369,7 @@ describe Yt::Video, :partner do
|
|
377
369
|
|
378
370
|
describe 'lost subscribers can be retrieved for a specific day' do
|
379
371
|
context 'in which the video was partnered' do
|
380
|
-
let(:subscribers_lost) { video.subscribers_lost_on
|
372
|
+
let(:subscribers_lost) { video.subscribers_lost_on ENV['YT_TEST_PARTNER_VIDEO_DATE']}
|
381
373
|
it { expect(subscribers_lost).to be_a Float }
|
382
374
|
end
|
383
375
|
|
@@ -424,7 +416,7 @@ describe Yt::Video, :partner do
|
|
424
416
|
|
425
417
|
describe 'added favorites can be retrieved for a specific day' do
|
426
418
|
context 'in which the video was partnered' do
|
427
|
-
let(:favorites_added) { video.favorites_added_on
|
419
|
+
let(:favorites_added) { video.favorites_added_on ENV['YT_TEST_PARTNER_VIDEO_DATE']}
|
428
420
|
it { expect(favorites_added).to be_a Float }
|
429
421
|
end
|
430
422
|
|
@@ -471,7 +463,7 @@ describe Yt::Video, :partner do
|
|
471
463
|
|
472
464
|
describe 'removed favorites can be retrieved for a specific day' do
|
473
465
|
context 'in which the video was partnered' do
|
474
|
-
let(:favorites_removed) { video.favorites_removed_on
|
466
|
+
let(:favorites_removed) { video.favorites_removed_on ENV['YT_TEST_PARTNER_VIDEO_DATE']}
|
475
467
|
it { expect(favorites_removed).to be_a Float }
|
476
468
|
end
|
477
469
|
|
@@ -761,6 +753,58 @@ describe Yt::Video, :partner do
|
|
761
753
|
end
|
762
754
|
end
|
763
755
|
|
756
|
+
describe 'viewer percentage can be retrieved for a range of days' do
|
757
|
+
let(:viewer_percentage) { video.viewer_percentage since: 1.year.ago, until: 10.days.ago}
|
758
|
+
it { expect(viewer_percentage).to be_a Hash }
|
759
|
+
end
|
760
|
+
|
761
|
+
describe 'viewer_percentage can be grouped by gender and age group' do
|
762
|
+
let(:range) { {since: 1.year.ago.to_date, until: 1.week.ago.to_date} }
|
763
|
+
let(:keys) { range.values }
|
764
|
+
|
765
|
+
specify 'without a :by option (default)' do
|
766
|
+
viewer_percentage = video.viewer_percentage range
|
767
|
+
expect(viewer_percentage.keys).to match_array [:female, :male]
|
768
|
+
expect(viewer_percentage[:female].keys - %w(65- 35-44 45-54 13-17 25-34 55-64 18-24)).to be_empty
|
769
|
+
expect(viewer_percentage[:female].values).to all(be_instance_of Float)
|
770
|
+
expect(viewer_percentage[:male].keys - %w(65- 35-44 45-54 13-17 25-34 55-64 18-24)).to be_empty
|
771
|
+
expect(viewer_percentage[:male].values).to all(be_instance_of Float)
|
772
|
+
end
|
773
|
+
|
774
|
+
specify 'with the :by option set to :gender_age_group' do
|
775
|
+
viewer_percentage = video.viewer_percentage range.merge by: :gender_age_group
|
776
|
+
expect(viewer_percentage.keys).to match_array [:female, :male]
|
777
|
+
expect(viewer_percentage[:female].keys - %w(65- 35-44 45-54 13-17 25-34 55-64 18-24)).to be_empty
|
778
|
+
expect(viewer_percentage[:female].values).to all(be_instance_of Float)
|
779
|
+
expect(viewer_percentage[:male].keys - %w(65- 35-44 45-54 13-17 25-34 55-64 18-24)).to be_empty
|
780
|
+
expect(viewer_percentage[:male].values).to all(be_instance_of Float)
|
781
|
+
end
|
782
|
+
end
|
783
|
+
|
784
|
+
describe 'viewer_percentage can be grouped by gender' do
|
785
|
+
let(:range) { {since: 1.year.ago.to_date, until: 1.week.ago.to_date} }
|
786
|
+
let(:keys) { range.values }
|
787
|
+
|
788
|
+
specify 'with the :by option set to :gender' do
|
789
|
+
viewer_percentage = video.viewer_percentage range.merge by: :gender
|
790
|
+
expect(viewer_percentage.keys).to match_array [:female, :male]
|
791
|
+
expect(viewer_percentage[:female]).to be_a Float
|
792
|
+
expect(viewer_percentage[:male]).to be_a Float
|
793
|
+
end
|
794
|
+
end
|
795
|
+
|
796
|
+
describe 'viewer_percentage can be grouped by age group' do
|
797
|
+
let(:range) { {since: 1.year.ago.to_date, until: 1.week.ago.to_date} }
|
798
|
+
let(:keys) { range.values }
|
799
|
+
|
800
|
+
specify 'with the :by option set to :age_group' do
|
801
|
+
viewer_percentage = video.viewer_percentage range.merge by: :age_group
|
802
|
+
expect(viewer_percentage.keys - %w(65- 35-44 45-54 13-17 25-34 55-64 18-24)).to be_empty
|
803
|
+
expect(viewer_percentage.values).to all(be_instance_of Float)
|
804
|
+
end
|
805
|
+
end
|
806
|
+
|
807
|
+
# @deprecated, use video.viewer_percentage instead
|
764
808
|
specify 'viewer percentages by gender and age range can be retrieved' do
|
765
809
|
expect(video.viewer_percentages[:female]['18-24']).to be_a Float
|
766
810
|
expect(video.viewer_percentages[:female]['25-34']).to be_a Float
|
@@ -774,9 +818,6 @@ describe Yt::Video, :partner do
|
|
774
818
|
expect(video.viewer_percentages[:male]['45-54']).to be_a Float
|
775
819
|
expect(video.viewer_percentages[:male]['55-64']).to be_a Float
|
776
820
|
expect(video.viewer_percentages[:male]['65-']).to be_a Float
|
777
|
-
|
778
|
-
expect(video.viewer_percentage(gender: :male)).to be_a Float
|
779
|
-
expect(video.viewer_percentage(gender: :female)).to be_a Float
|
780
821
|
end
|
781
822
|
end
|
782
823
|
|
@@ -5,7 +5,7 @@ describe Yt::PlaylistItem, :server_app do
|
|
5
5
|
subject(:item) { Yt::PlaylistItem.new id: id }
|
6
6
|
|
7
7
|
context 'given an existing playlist item' do
|
8
|
-
let(:id) { '
|
8
|
+
let(:id) { 'PLjW_GNR5Ir0GMlbJzA-aW0UV8TchJFb8p3uzrLNcZKPY' }
|
9
9
|
|
10
10
|
it 'returns valid snippet data' do
|
11
11
|
expect(item.snippet).to be_a Yt::Snippet
|
@@ -5,7 +5,7 @@ describe Yt::Playlist, :server_app do
|
|
5
5
|
subject(:playlist) { Yt::Playlist.new id: id }
|
6
6
|
|
7
7
|
context 'given an existing playlist' do
|
8
|
-
let(:id) { '
|
8
|
+
let(:id) { 'PLSWYkYzOrPMT9pJG5St5G0WDalhRzGkU4' }
|
9
9
|
|
10
10
|
it 'returns valid snippet data' do
|
11
11
|
expect(playlist.snippet).to be_a Yt::Snippet
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.15.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Claudio Baccigalupo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|