yt 0.7.3 → 0.7.4
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/.yardopts +2 -0
- data/Gemfile.lock +2 -2
- data/HISTORY.md +2 -0
- data/README.md +9 -7
- data/lib/yt/collections/reports.rb +2 -6
- data/lib/yt/models/account.rb +3 -2
- data/lib/yt/models/base.rb +3 -33
- data/lib/yt/models/channel.rb +24 -4
- data/lib/yt/modules/associations.rb +47 -0
- data/lib/yt/{associations/authentications.rb → modules/authentication.rb} +2 -2
- data/lib/yt/modules/reports.rb +65 -0
- data/lib/yt/version.rb +1 -1
- data/spec/{associations/device_auth → requests/as_account}/account_spec.rb +0 -0
- data/spec/{associations/device_auth → requests/as_account}/authentications_spec.rb +2 -2
- data/spec/{associations/device_auth → requests/as_account}/channel_spec.rb +0 -1
- data/spec/{associations/device_auth → requests/as_account}/playlist_item_spec.rb +0 -0
- data/spec/{associations/device_auth → requests/as_account}/playlist_spec.rb +0 -0
- data/spec/{associations/device_auth → requests/as_account}/resource_spec.rb +0 -0
- data/spec/{associations/device_auth → requests/as_account}/video_spec.rb +0 -0
- data/spec/requests/as_content_owner/channel_spec.rb +245 -0
- data/spec/{associations/device_auth → requests/as_content_owner}/content_owner_spec.rb +0 -0
- data/spec/{associations/server_auth → requests/as_server_app}/channel_spec.rb +0 -0
- data/spec/{associations/server_auth → requests/as_server_app}/playlist_item_spec.rb +0 -0
- data/spec/{associations/server_auth → requests/as_server_app}/playlist_spec.rb +0 -0
- data/spec/{associations/server_auth → requests/as_server_app}/resource_spec.rb +0 -0
- data/spec/{associations/server_auth → requests/as_server_app}/video_spec.rb +0 -0
- data/spec/{associations/no_auth → requests/unauthenticated}/video_spec.rb +2 -2
- metadata +34 -40
- data/lib/yt/associations/earnings.rb +0 -44
- data/lib/yt/associations/views.rb +0 -44
- data/lib/yt/collections/earnings.rb +0 -14
- data/lib/yt/collections/views.rb +0 -18
- data/spec/associations/device_auth/earnings_spec.rb +0 -67
- data/spec/associations/device_auth/views_spec.rb +0 -52
- data/spec/collections/earnings_spec.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3db26d07a5ba0fed297bba2c49bf6d3124620f48
|
4
|
+
data.tar.gz: 9fdda77579c877c307fbd36880744ca89a925b29
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee58c92e64c053f44f05634012be1804841db856118917c9a02539a47267bedc1c3e4b2f662988fac7c33fd1688db71fe45f1aabed3773da78e0a8dfe3710d0a
|
7
|
+
data.tar.gz: 3fa6e55ee78ec12f9e9a6810f8a7260fd2d62313758324cb984e2f3655a784af60504614796d18f0107e9ad64ffa221df202283fb64537bcf1630e8d549a6746
|
data/.yardopts
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
yt (0.7.
|
4
|
+
yt (0.7.4)
|
5
5
|
activesupport
|
6
6
|
|
7
7
|
GEM
|
@@ -24,7 +24,7 @@ GEM
|
|
24
24
|
i18n (0.6.9)
|
25
25
|
json (1.8.1)
|
26
26
|
mime-types (2.3)
|
27
|
-
minitest (5.3.
|
27
|
+
minitest (5.3.5)
|
28
28
|
multi_json (1.10.1)
|
29
29
|
rake (10.3.2)
|
30
30
|
rest-client (1.6.7)
|
data/HISTORY.md
CHANGED
@@ -10,6 +10,8 @@ v0.7 - 2014/06/18
|
|
10
10
|
* More status methods for PlaylistItem (privacy_status, public?, private?, unlisted?)
|
11
11
|
* Add video.update to update title, description, tags and categoryId of a video
|
12
12
|
* Sort channel.videos by most recent first
|
13
|
+
* Extract Reports (earnings, views) into module with macro `has_report`
|
14
|
+
* New channel reports: comments, likes, dislikes, shares and impressions
|
13
15
|
|
14
16
|
v0.6 - 2014/06/05
|
15
17
|
-----------------
|
data/README.md
CHANGED
@@ -86,7 +86,7 @@ Use [Yt::Channel](http://rubydoc.info/github/Fullscreen/yt/master/Yt/Models/Chan
|
|
86
86
|
* access the playlists of a channel
|
87
87
|
* subscribe to and unsubscribe from a channel
|
88
88
|
* create and delete playlists from a channel
|
89
|
-
* retrieve the
|
89
|
+
* retrieve the daily earnings, views, comments, likes, dislikes, shares and impressions of a channel
|
90
90
|
|
91
91
|
```ruby
|
92
92
|
channel = Yt::Channel.new id: 'UCxO1tY8h1AhOz0T4ENwmpow'
|
@@ -131,10 +131,12 @@ content_owner = Yt::ContentOwner.new owner_name: 'CMSname', access_token: 'ya29.
|
|
131
131
|
channel = Yt::Channel.new id: 'UCxO1tY8h1AhOz0T4ENwmpow', auth: content_owner
|
132
132
|
|
133
133
|
channel.earnings_on 5.days.ago #=> 12.23
|
134
|
-
channel.
|
135
|
-
|
136
|
-
channel.
|
137
|
-
channel.
|
134
|
+
channel.views since: 7.days.ago #=> {Wed, 28 May 2014 => 12.0, Thu, 29 May 2014 => 3.0, …}
|
135
|
+
channel.comments until: 2.days.ago #=> {Wed, 28 May 2014 => 9.0, Thu, 29 May 2014 => 4.0, …}
|
136
|
+
channel.ch.likes from: 8.days.ago #=> {Tue, 27 May 2014 => 7.0, Wed, 28 May 2014 => 0.0, …}
|
137
|
+
channel.ch.dislikes to: 2.days.ago #=> {Tue, 27 May 2014 => 0.0, Wed, 28 May 2014 => 1.0, …}
|
138
|
+
channel.shares since: 7.days.ago, until: 7.days.ago #=> {Wed, 28 May 2014 => 3.0}
|
139
|
+
channel.impressions_on 5.days.ago #=> 157.0
|
138
140
|
```
|
139
141
|
|
140
142
|
*The methods above require to be authenticated as the channel’s content owner (see below).*
|
@@ -431,7 +433,7 @@ To install on your system, run
|
|
431
433
|
|
432
434
|
To use inside a bundled Ruby project, add this line to the Gemfile:
|
433
435
|
|
434
|
-
gem 'yt', '~> 0.7.
|
436
|
+
gem 'yt', '~> 0.7.4'
|
435
437
|
|
436
438
|
Since the gem follows [Semantic Versioning](http://semver.org),
|
437
439
|
indicating the full version in your Gemfile (~> *major*.*minor*.*patch*)
|
@@ -459,7 +461,7 @@ How to test
|
|
459
461
|
Yt comes with two different sets of tests:
|
460
462
|
|
461
463
|
1. tests in `spec/models`, `spec/collections` and `spec/errors` **do not hit** the YouTube API
|
462
|
-
1. tests in `spec/
|
464
|
+
1. tests in `spec/requests` **hit** the YouTube API and require authentication
|
463
465
|
|
464
466
|
The reason why some tests actually hit the YouTube API is because they are
|
465
467
|
meant to really integrate Yt with YouTube. YouTube API is not exactly
|
@@ -3,6 +3,7 @@ require 'yt/collections/base'
|
|
3
3
|
module Yt
|
4
4
|
module Collections
|
5
5
|
class Reports < Base
|
6
|
+
attr_writer :metric
|
6
7
|
|
7
8
|
def within(days_range)
|
8
9
|
@days_range = days_range
|
@@ -24,7 +25,7 @@ module Yt
|
|
24
25
|
params['filters'] = "channel==#{@parent.id}"
|
25
26
|
params['start-date'] = @days_range.begin
|
26
27
|
params['end-date'] = @days_range.end
|
27
|
-
params['metrics'] =
|
28
|
+
params['metrics'] = @metric
|
28
29
|
params['dimensions'] = :day
|
29
30
|
end
|
30
31
|
end
|
@@ -40,11 +41,6 @@ module Yt
|
|
40
41
|
data.last
|
41
42
|
end
|
42
43
|
|
43
|
-
# To be overriden by superclasses
|
44
|
-
# def metrics
|
45
|
-
# ''
|
46
|
-
# end
|
47
|
-
|
48
44
|
def items_key
|
49
45
|
'rows'
|
50
46
|
end
|
data/lib/yt/models/account.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
require 'yt/models/base'
|
2
|
-
require 'yt/
|
2
|
+
require 'yt/modules/authentication'
|
3
3
|
|
4
4
|
module Yt
|
5
5
|
module Models
|
6
6
|
# Provides methods to interact with YouTube accounts.
|
7
7
|
# @see https://developers.google.com/youtube/v3/guides/authentication
|
8
8
|
class Account < Base
|
9
|
-
|
9
|
+
# Includes methods to authenticate with YouTube API.
|
10
|
+
include Modules::Authentication
|
10
11
|
|
11
12
|
# @!attribute [r] channel
|
12
13
|
# @return [Yt::Models::Channel] the account’s channel.
|
data/lib/yt/models/base.rb
CHANGED
@@ -1,45 +1,15 @@
|
|
1
1
|
require 'yt/actions/delete'
|
2
2
|
require 'yt/actions/update'
|
3
|
+
require 'yt/modules/associations'
|
3
4
|
require 'yt/errors/request_error'
|
4
5
|
|
5
|
-
require 'active_support' # does not load anything by default but is required
|
6
|
-
require 'active_support/core_ext/module/delegation' # for delegate
|
7
|
-
require 'active_support/core_ext/string/inflections' # for camelize/constantize
|
8
|
-
|
9
6
|
module Yt
|
10
7
|
module Models
|
11
8
|
class Base
|
9
|
+
extend Modules::Associations
|
10
|
+
|
12
11
|
include Actions::Delete
|
13
12
|
include Actions::Update
|
14
|
-
|
15
|
-
# @private
|
16
|
-
def self.has_many(attributes)
|
17
|
-
require "yt/collections/#{attributes}"
|
18
|
-
collection_name = attributes.to_s.sub(/.*\./, '').camelize.pluralize
|
19
|
-
collection = "Yt::Collections::#{collection_name}".constantize
|
20
|
-
define_memoized_method(attributes) { collection.of self }
|
21
|
-
end
|
22
|
-
|
23
|
-
# @private
|
24
|
-
def self.has_one(attribute)
|
25
|
-
attributes = attribute.to_s.pluralize
|
26
|
-
has_many attributes
|
27
|
-
define_memoized_method(attribute) { send(attributes).first! }
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
# A wrapper around Ruby’s +define_method+ that, in addition to adding an
|
33
|
-
# instance method called +name+, adds an instance variable called +@name+
|
34
|
-
# that stores the result of +name+ the first time is invoked, and returns
|
35
|
-
# it every other time. Especially useful if invoking +name+ takes a long
|
36
|
-
# time.
|
37
|
-
def self.define_memoized_method(name, &method)
|
38
|
-
define_method name do
|
39
|
-
ivar = instance_variable_get "@#{name}"
|
40
|
-
instance_variable_set "@#{name}", ivar || instance_eval(&method)
|
41
|
-
end
|
42
|
-
end
|
43
13
|
end
|
44
14
|
end
|
45
15
|
|
data/lib/yt/models/channel.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
require 'yt/models/resource'
|
2
|
-
require 'yt/
|
3
|
-
require 'yt/associations/views'
|
2
|
+
require 'yt/modules/reports'
|
4
3
|
|
5
4
|
module Yt
|
6
5
|
module Models
|
7
6
|
# A channel resource contains information about a YouTube channel.
|
8
7
|
# @see https://developers.google.com/youtube/v3/docs/channels
|
9
8
|
class Channel < Resource
|
10
|
-
|
11
|
-
|
9
|
+
# Includes the +:has_report+ method to access YouTube Analytics reports.
|
10
|
+
extend Modules::Reports
|
12
11
|
|
13
12
|
# @!attribute [r] subscriptions
|
14
13
|
# @return [Yt::Collections::Subscriptions] the channel’s subscriptions.
|
@@ -22,6 +21,27 @@ module Yt
|
|
22
21
|
# @return [Yt::Collections::Playlists] the channel’s playlists.
|
23
22
|
has_many :playlists
|
24
23
|
|
24
|
+
# @macro has_report
|
25
|
+
has_report :earnings
|
26
|
+
|
27
|
+
# @macro has_report
|
28
|
+
has_report :views
|
29
|
+
|
30
|
+
# @macro has_report
|
31
|
+
has_report :comments
|
32
|
+
|
33
|
+
# @macro has_report
|
34
|
+
has_report :likes
|
35
|
+
|
36
|
+
# @macro has_report
|
37
|
+
has_report :dislikes
|
38
|
+
|
39
|
+
# @macro has_report
|
40
|
+
has_report :shares
|
41
|
+
|
42
|
+
# @macro has_report
|
43
|
+
has_report :impressions
|
44
|
+
|
25
45
|
# @!attribute [r] statistics_set
|
26
46
|
# @return [Yt::Models::StatisticsSet] the statistics for the video.
|
27
47
|
has_one :statistics_set
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'active_support' # does not load anything by default but is required
|
2
|
+
require 'active_support/core_ext/module/delegation' # for delegate
|
3
|
+
require 'active_support/core_ext/string/inflections' # for camelize/constantize
|
4
|
+
|
5
|
+
module Yt
|
6
|
+
module Modules
|
7
|
+
# Associations are a set of macro-like class methods to express
|
8
|
+
# relationship between YouTube resources like "Channel has many Videos" or
|
9
|
+
# "Account has one Id". They are inspired by ActiveRecord::Associations.
|
10
|
+
module Associations
|
11
|
+
# @example Adds the +videos+ method to the Channel resource.
|
12
|
+
# class Channel < Resource
|
13
|
+
# has_many :videos
|
14
|
+
# end
|
15
|
+
def has_many(attributes)
|
16
|
+
require "yt/collections/#{attributes}"
|
17
|
+
collection_name = attributes.to_s.sub(/.*\./, '').camelize.pluralize
|
18
|
+
collection = "Yt::Collections::#{collection_name}".constantize
|
19
|
+
define_memoized_method(attributes) { collection.of self }
|
20
|
+
end
|
21
|
+
|
22
|
+
# @example Adds the +status+ method to the Video resource.
|
23
|
+
# class Video < Resource
|
24
|
+
# has_one :status
|
25
|
+
# end
|
26
|
+
def has_one(attribute)
|
27
|
+
attributes = attribute.to_s.pluralize
|
28
|
+
has_many attributes
|
29
|
+
define_memoized_method(attribute) { send(attributes).first! }
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# A wrapper around Ruby’s +define_method+ that, in addition to adding an
|
35
|
+
# instance method called +name+, adds an instance variable called +@name+
|
36
|
+
# that stores the result of +name+ the first time is invoked, and returns
|
37
|
+
# it every other time. Especially useful if invoking +name+ takes a long
|
38
|
+
# time.
|
39
|
+
def define_memoized_method(name, &method)
|
40
|
+
define_method name do
|
41
|
+
ivar = instance_variable_get "@#{name}"
|
42
|
+
instance_variable_set "@#{name}", ivar || instance_eval(&method)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -4,12 +4,12 @@ require 'yt/errors/no_items'
|
|
4
4
|
require 'yt/errors/unauthorized'
|
5
5
|
|
6
6
|
module Yt
|
7
|
-
module
|
7
|
+
module Modules
|
8
8
|
# Provides authentication methods to YouTube resources, which
|
9
9
|
# allows to access to content detail set-specific methods like `access_token`.
|
10
10
|
#
|
11
11
|
# YouTube resources with authentication are: {Yt::Models::Account accounts}.
|
12
|
-
module
|
12
|
+
module Authentication
|
13
13
|
delegate :access_token, :refresh_token, :expires_at, to: :authentication
|
14
14
|
|
15
15
|
def initialize(options = {})
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'yt/collections/reports'
|
2
|
+
|
3
|
+
module Yt
|
4
|
+
module Modules
|
5
|
+
# Provides methods to to access the analytics reports of a resource.
|
6
|
+
#
|
7
|
+
# YouTube resources with reports are: {Yt::Models::Channel channels}.
|
8
|
+
module Reports
|
9
|
+
# @!macro has_report
|
10
|
+
# @!method $1_on(date)
|
11
|
+
# @return [Float] the $1 for a single day.
|
12
|
+
# @param [#to_date] date The single day to get the $1 for.
|
13
|
+
# @!method $1(options = {})
|
14
|
+
# @return [Hash<Date, Float>] the $1 for a range of a days.
|
15
|
+
# @param [Hash] options the range of days to get the $1 for.
|
16
|
+
# @option options [#to_date] :since The first day of the range.
|
17
|
+
# Also aliased as *:from*.
|
18
|
+
# @option options [#to_date] :until The last day of the range.
|
19
|
+
# Also aliased as *:to*.
|
20
|
+
|
21
|
+
# Defines two public instance methods to access the reports of a
|
22
|
+
# resource for a specific metric.
|
23
|
+
# @param [Symbol] metric the metric to access the reports of.
|
24
|
+
# @example Adds +earnings+ and +earnings_on+ on a Channel resource.
|
25
|
+
# class Channel < Resource
|
26
|
+
# has_report :earnings
|
27
|
+
# end
|
28
|
+
def has_report(metric)
|
29
|
+
define_method "#{metric}_on" do |date|
|
30
|
+
send(metric, from: date, to: date).values.first
|
31
|
+
end
|
32
|
+
|
33
|
+
define_method metric do |options = {}|
|
34
|
+
from = options[:since] || options[:from] || 5.days.ago
|
35
|
+
to = options[:until] || options[:to] || 1.day.ago
|
36
|
+
range = Range.new *[from, to].map(&:to_date)
|
37
|
+
|
38
|
+
ivar = instance_variable_get "@#{metric}"
|
39
|
+
instance_variable_set "@#{metric}", ivar || {}
|
40
|
+
|
41
|
+
Hash[*range.flat_map do |date|
|
42
|
+
[date, instance_variable_get("@#{metric}")[date] ||= send("range_#{metric}", range)[date]]
|
43
|
+
end]
|
44
|
+
end
|
45
|
+
|
46
|
+
define_method "range_#{metric}" do |date_range|
|
47
|
+
ivar = instance_variable_get "@range_#{metric}"
|
48
|
+
instance_variable_set "@range_#{metric}", ivar || {}
|
49
|
+
instance_variable_get("@range_#{metric}")[date_range] ||= send("all_#{metric}").within date_range
|
50
|
+
end
|
51
|
+
private "range_#{metric}"
|
52
|
+
|
53
|
+
define_method "all_#{metric}" do
|
54
|
+
# @note Asking for the "earnings" metric of a day in which a channel
|
55
|
+
# made 0 USD returns the wrong "nil". But adding to the request the
|
56
|
+
# "estimatedMinutesWatched" metric returns the correct value 0.
|
57
|
+
query = metric
|
58
|
+
query = "estimatedMinutesWatched,#{metric}" if metric == :earnings
|
59
|
+
Collections::Reports.of(self).tap{|reports| reports.metric = query}
|
60
|
+
end
|
61
|
+
private "all_#{metric}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/yt/version.rb
CHANGED
File without changes
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'yt/
|
2
|
+
require 'yt/models/account'
|
3
3
|
|
4
|
-
describe Yt::
|
4
|
+
describe Yt::Account, :device_app do
|
5
5
|
subject(:account) { Yt::Account.new attrs }
|
6
6
|
|
7
7
|
describe '#refresh' do
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,245 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'yt/models/channel'
|
4
|
+
|
5
|
+
describe Yt::Channel, :partner do
|
6
|
+
subject(:channel) { Yt::Channel.new id: id, auth: $content_owner }
|
7
|
+
|
8
|
+
context 'given a partnered channel', :partner do
|
9
|
+
context 'managed by the authenticated Content Owner' do
|
10
|
+
let(:id) { ENV['YT_TEST_PARTNER_CHANNEL_ID'] }
|
11
|
+
|
12
|
+
describe 'earnings can be retrieved for a specific day' do
|
13
|
+
context 'in which the channel made any money' do
|
14
|
+
let(:earnings) { channel.earnings_on 5.days.ago}
|
15
|
+
it { expect(earnings).to be_a Float }
|
16
|
+
end
|
17
|
+
|
18
|
+
# NOTE: This test sounds redundant, but it’s actually a reflection of
|
19
|
+
# another irrational behavior of YouTube API. In short, if you ask for
|
20
|
+
# the "earnings" metric of a day in which a channel made 0 USD, then
|
21
|
+
# the API returns "nil". But if you also for the "earnings" metric AND
|
22
|
+
# the "estimatedMinutesWatched" metric, then the API returns the
|
23
|
+
# correct value of "0", while still returning nil for those days in
|
24
|
+
# which the earnings have not been estimated yet.
|
25
|
+
context 'in which the channel did not make any money' do
|
26
|
+
let(:zero_date) { ENV['YT_TEST_PARTNER_CHANNEL_NO_EARNINGS_DATE'] }
|
27
|
+
let(:earnings) { channel.earnings_on zero_date}
|
28
|
+
it { expect(earnings).to eq 0 }
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'in the future' do
|
32
|
+
let(:earnings) { channel.earnings_on 5.days.from_now}
|
33
|
+
it { expect(earnings).to be_nil }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'earnings can be retrieved for a range of days' do
|
38
|
+
let(:date) { 4.days.ago }
|
39
|
+
|
40
|
+
specify 'with a given start (:since option)' do
|
41
|
+
expect(channel.earnings(since: date).keys.min).to eq date.to_date
|
42
|
+
end
|
43
|
+
|
44
|
+
specify 'with a given end (:until option)' do
|
45
|
+
expect(channel.earnings(until: date).keys.max).to eq date.to_date
|
46
|
+
end
|
47
|
+
|
48
|
+
specify 'with a given start (:from option)' do
|
49
|
+
expect(channel.earnings(from: date).keys.min).to eq date.to_date
|
50
|
+
end
|
51
|
+
|
52
|
+
specify 'with a given end (:to option)' do
|
53
|
+
expect(channel.earnings(to: date).keys.max).to eq date.to_date
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'views can be retrieved for a specific day' do
|
58
|
+
context 'in which the channel was partnered' do
|
59
|
+
let(:views) { channel.views_on 5.days.ago}
|
60
|
+
it { expect(views).to be_a Float }
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'in which the channel was not partnered' do
|
64
|
+
let(:views) { channel.views_on 20.years.ago}
|
65
|
+
it { expect(views).to be_nil }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe 'views can be retrieved for a range of days' do
|
70
|
+
let(:date) { 4.days.ago }
|
71
|
+
|
72
|
+
specify 'with a given start (:since option)' do
|
73
|
+
expect(channel.views(since: date).keys.min).to eq date.to_date
|
74
|
+
end
|
75
|
+
|
76
|
+
specify 'with a given end (:until option)' do
|
77
|
+
expect(channel.views(until: date).keys.max).to eq date.to_date
|
78
|
+
end
|
79
|
+
|
80
|
+
specify 'with a given start (:from option)' do
|
81
|
+
expect(channel.views(from: date).keys.min).to eq date.to_date
|
82
|
+
end
|
83
|
+
|
84
|
+
specify 'with a given end (:to option)' do
|
85
|
+
expect(channel.views(to: date).keys.max).to eq date.to_date
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe 'comments can be retrieved for a specific day' do
|
90
|
+
context 'in which the channel was partnered' do
|
91
|
+
let(:comments) { channel.comments_on 5.days.ago}
|
92
|
+
it { expect(comments).to be_a Float }
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'in which the channel was not partnered' do
|
96
|
+
let(:comments) { channel.comments_on 20.years.ago}
|
97
|
+
it { expect(comments).to be_nil }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe 'comments can be retrieved for a range of days' do
|
102
|
+
let(:date) { 4.days.ago }
|
103
|
+
|
104
|
+
specify 'with a given start (:since option)' do
|
105
|
+
expect(channel.comments(since: date).keys.min).to eq date.to_date
|
106
|
+
end
|
107
|
+
|
108
|
+
specify 'with a given end (:until option)' do
|
109
|
+
expect(channel.comments(until: date).keys.max).to eq date.to_date
|
110
|
+
end
|
111
|
+
|
112
|
+
specify 'with a given start (:from option)' do
|
113
|
+
expect(channel.comments(from: date).keys.min).to eq date.to_date
|
114
|
+
end
|
115
|
+
|
116
|
+
specify 'with a given end (:to option)' do
|
117
|
+
expect(channel.comments(to: date).keys.max).to eq date.to_date
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe 'likes can be retrieved for a specific day' do
|
122
|
+
context 'in which the channel was partnered' do
|
123
|
+
let(:likes) { channel.likes_on 5.days.ago}
|
124
|
+
it { expect(likes).to be_a Float }
|
125
|
+
end
|
126
|
+
|
127
|
+
context 'in which the channel was not partnered' do
|
128
|
+
let(:likes) { channel.likes_on 20.years.ago}
|
129
|
+
it { expect(likes).to be_nil }
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe 'likes can be retrieved for a range of days' do
|
134
|
+
let(:date) { 4.days.ago }
|
135
|
+
|
136
|
+
specify 'with a given start (:since option)' do
|
137
|
+
expect(channel.likes(since: date).keys.min).to eq date.to_date
|
138
|
+
end
|
139
|
+
|
140
|
+
specify 'with a given end (:until option)' do
|
141
|
+
expect(channel.likes(until: date).keys.max).to eq date.to_date
|
142
|
+
end
|
143
|
+
|
144
|
+
specify 'with a given start (:from option)' do
|
145
|
+
expect(channel.likes(from: date).keys.min).to eq date.to_date
|
146
|
+
end
|
147
|
+
|
148
|
+
specify 'with a given end (:to option)' do
|
149
|
+
expect(channel.likes(to: date).keys.max).to eq date.to_date
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe 'dislikes can be retrieved for a specific day' do
|
154
|
+
context 'in which the channel was partnered' do
|
155
|
+
let(:dislikes) { channel.dislikes_on 5.days.ago}
|
156
|
+
it { expect(dislikes).to be_a Float }
|
157
|
+
end
|
158
|
+
|
159
|
+
context 'in which the channel was not partnered' do
|
160
|
+
let(:dislikes) { channel.dislikes_on 20.years.ago}
|
161
|
+
it { expect(dislikes).to be_nil }
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe 'dislikes can be retrieved for a range of days' do
|
166
|
+
let(:date) { 4.days.ago }
|
167
|
+
|
168
|
+
specify 'with a given start (:since option)' do
|
169
|
+
expect(channel.dislikes(since: date).keys.min).to eq date.to_date
|
170
|
+
end
|
171
|
+
|
172
|
+
specify 'with a given end (:until option)' do
|
173
|
+
expect(channel.dislikes(until: date).keys.max).to eq date.to_date
|
174
|
+
end
|
175
|
+
|
176
|
+
specify 'with a given start (:from option)' do
|
177
|
+
expect(channel.dislikes(from: date).keys.min).to eq date.to_date
|
178
|
+
end
|
179
|
+
|
180
|
+
specify 'with a given end (:to option)' do
|
181
|
+
expect(channel.dislikes(to: date).keys.max).to eq date.to_date
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
describe 'shares can be retrieved for a range of days' do
|
186
|
+
let(:date) { 4.days.ago }
|
187
|
+
|
188
|
+
specify 'with a given start (:since option)' do
|
189
|
+
expect(channel.shares(since: date).keys.min).to eq date.to_date
|
190
|
+
end
|
191
|
+
|
192
|
+
specify 'with a given end (:until option)' do
|
193
|
+
expect(channel.shares(until: date).keys.max).to eq date.to_date
|
194
|
+
end
|
195
|
+
|
196
|
+
specify 'with a given start (:from option)' do
|
197
|
+
expect(channel.shares(from: date).keys.min).to eq date.to_date
|
198
|
+
end
|
199
|
+
|
200
|
+
specify 'with a given end (:to option)' do
|
201
|
+
expect(channel.shares(to: date).keys.max).to eq date.to_date
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe 'impressions can be retrieved for a specific day' do
|
206
|
+
context 'in which the channel was partnered' do
|
207
|
+
let(:impressions) { channel.impressions_on 5.days.ago}
|
208
|
+
it { expect(impressions).to be_a Float }
|
209
|
+
end
|
210
|
+
|
211
|
+
context 'in which the channel was not partnered' do
|
212
|
+
let(:impressions) { channel.impressions_on 20.years.ago}
|
213
|
+
it { expect(impressions).to be_nil }
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
describe 'impressions can be retrieved for a range of days' do
|
218
|
+
let(:date) { 4.days.ago }
|
219
|
+
|
220
|
+
specify 'with a given start (:since option)' do
|
221
|
+
expect(channel.impressions(since: date).keys.min).to eq date.to_date
|
222
|
+
end
|
223
|
+
|
224
|
+
specify 'with a given end (:until option)' do
|
225
|
+
expect(channel.impressions(until: date).keys.max).to eq date.to_date
|
226
|
+
end
|
227
|
+
|
228
|
+
specify 'with a given start (:from option)' do
|
229
|
+
expect(channel.impressions(from: date).keys.min).to eq date.to_date
|
230
|
+
end
|
231
|
+
|
232
|
+
specify 'with a given end (:to option)' do
|
233
|
+
expect(channel.impressions(to: date).keys.max).to eq date.to_date
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
context 'not managed by the authenticated Content Owner' do
|
239
|
+
let(:id) { 'UCBR8-60-B28hp2BmDPdntcQ' }
|
240
|
+
|
241
|
+
it { expect{channel.earnings}.to raise_error Yt::Errors::Forbidden }
|
242
|
+
it { expect{channel.views}.to raise_error Yt::Errors::Forbidden }
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'yt/models/video'
|
3
3
|
|
4
|
-
describe Yt::Video
|
5
|
-
subject(:video) { Yt::Video.new id: id
|
4
|
+
describe Yt::Video do
|
5
|
+
subject(:video) { Yt::Video.new id: id }
|
6
6
|
|
7
7
|
context 'given a public video with annotations' do
|
8
8
|
let(:id) { 'MESycYJytkU' }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Claudio Baccigalupo
|
@@ -122,15 +122,11 @@ files:
|
|
122
122
|
- lib/yt/actions/insert.rb
|
123
123
|
- lib/yt/actions/list.rb
|
124
124
|
- lib/yt/actions/update.rb
|
125
|
-
- lib/yt/associations/authentications.rb
|
126
|
-
- lib/yt/associations/earnings.rb
|
127
|
-
- lib/yt/associations/views.rb
|
128
125
|
- lib/yt/collections/annotations.rb
|
129
126
|
- lib/yt/collections/authentications.rb
|
130
127
|
- lib/yt/collections/base.rb
|
131
128
|
- lib/yt/collections/channels.rb
|
132
129
|
- lib/yt/collections/content_details.rb
|
133
|
-
- lib/yt/collections/earnings.rb
|
134
130
|
- lib/yt/collections/ids.rb
|
135
131
|
- lib/yt/collections/partnered_channels.rb
|
136
132
|
- lib/yt/collections/playlist_items.rb
|
@@ -143,7 +139,6 @@ files:
|
|
143
139
|
- lib/yt/collections/subscriptions.rb
|
144
140
|
- lib/yt/collections/user_infos.rb
|
145
141
|
- lib/yt/collections/videos.rb
|
146
|
-
- lib/yt/collections/views.rb
|
147
142
|
- lib/yt/config.rb
|
148
143
|
- lib/yt/errors/forbidden.rb
|
149
144
|
- lib/yt/errors/no_items.rb
|
@@ -172,27 +167,13 @@ files:
|
|
172
167
|
- lib/yt/models/url.rb
|
173
168
|
- lib/yt/models/user_info.rb
|
174
169
|
- lib/yt/models/video.rb
|
170
|
+
- lib/yt/modules/associations.rb
|
171
|
+
- lib/yt/modules/authentication.rb
|
172
|
+
- lib/yt/modules/reports.rb
|
175
173
|
- lib/yt/version.rb
|
176
|
-
- spec/associations/device_auth/account_spec.rb
|
177
|
-
- spec/associations/device_auth/authentications_spec.rb
|
178
|
-
- spec/associations/device_auth/channel_spec.rb
|
179
|
-
- spec/associations/device_auth/content_owner_spec.rb
|
180
|
-
- spec/associations/device_auth/earnings_spec.rb
|
181
|
-
- spec/associations/device_auth/playlist_item_spec.rb
|
182
|
-
- spec/associations/device_auth/playlist_spec.rb
|
183
|
-
- spec/associations/device_auth/resource_spec.rb
|
184
|
-
- spec/associations/device_auth/video_spec.rb
|
185
|
-
- spec/associations/device_auth/views_spec.rb
|
186
|
-
- spec/associations/no_auth/video_spec.rb
|
187
|
-
- spec/associations/server_auth/channel_spec.rb
|
188
|
-
- spec/associations/server_auth/playlist_item_spec.rb
|
189
|
-
- spec/associations/server_auth/playlist_spec.rb
|
190
|
-
- spec/associations/server_auth/resource_spec.rb
|
191
|
-
- spec/associations/server_auth/video_spec.rb
|
192
174
|
- spec/collections/annotations_spec.rb
|
193
175
|
- spec/collections/channels_spec.rb
|
194
176
|
- spec/collections/content_details_spec.rb
|
195
|
-
- spec/collections/earnings_spec.rb
|
196
177
|
- spec/collections/playlist_items_spec.rb
|
197
178
|
- spec/collections/playlists_spec.rb
|
198
179
|
- spec/collections/ratings_spec.rb
|
@@ -221,6 +202,21 @@ files:
|
|
221
202
|
- spec/models/url_spec.rb
|
222
203
|
- spec/models/user_info_spec.rb
|
223
204
|
- spec/models/video_spec.rb
|
205
|
+
- spec/requests/as_account/account_spec.rb
|
206
|
+
- spec/requests/as_account/authentications_spec.rb
|
207
|
+
- spec/requests/as_account/channel_spec.rb
|
208
|
+
- spec/requests/as_account/playlist_item_spec.rb
|
209
|
+
- spec/requests/as_account/playlist_spec.rb
|
210
|
+
- spec/requests/as_account/resource_spec.rb
|
211
|
+
- spec/requests/as_account/video_spec.rb
|
212
|
+
- spec/requests/as_content_owner/channel_spec.rb
|
213
|
+
- spec/requests/as_content_owner/content_owner_spec.rb
|
214
|
+
- spec/requests/as_server_app/channel_spec.rb
|
215
|
+
- spec/requests/as_server_app/playlist_item_spec.rb
|
216
|
+
- spec/requests/as_server_app/playlist_spec.rb
|
217
|
+
- spec/requests/as_server_app/resource_spec.rb
|
218
|
+
- spec/requests/as_server_app/video_spec.rb
|
219
|
+
- spec/requests/unauthenticated/video_spec.rb
|
224
220
|
- spec/spec_helper.rb
|
225
221
|
- spec/support/fail_matcher.rb
|
226
222
|
- spec/support/global_hooks.rb
|
@@ -251,26 +247,9 @@ specification_version: 4
|
|
251
247
|
summary: Yt makes it easy to interact with Youtube V3 API by providing a modular,
|
252
248
|
intuitive and tested Ruby-style API.
|
253
249
|
test_files:
|
254
|
-
- spec/associations/device_auth/account_spec.rb
|
255
|
-
- spec/associations/device_auth/authentications_spec.rb
|
256
|
-
- spec/associations/device_auth/channel_spec.rb
|
257
|
-
- spec/associations/device_auth/content_owner_spec.rb
|
258
|
-
- spec/associations/device_auth/earnings_spec.rb
|
259
|
-
- spec/associations/device_auth/playlist_item_spec.rb
|
260
|
-
- spec/associations/device_auth/playlist_spec.rb
|
261
|
-
- spec/associations/device_auth/resource_spec.rb
|
262
|
-
- spec/associations/device_auth/video_spec.rb
|
263
|
-
- spec/associations/device_auth/views_spec.rb
|
264
|
-
- spec/associations/no_auth/video_spec.rb
|
265
|
-
- spec/associations/server_auth/channel_spec.rb
|
266
|
-
- spec/associations/server_auth/playlist_item_spec.rb
|
267
|
-
- spec/associations/server_auth/playlist_spec.rb
|
268
|
-
- spec/associations/server_auth/resource_spec.rb
|
269
|
-
- spec/associations/server_auth/video_spec.rb
|
270
250
|
- spec/collections/annotations_spec.rb
|
271
251
|
- spec/collections/channels_spec.rb
|
272
252
|
- spec/collections/content_details_spec.rb
|
273
|
-
- spec/collections/earnings_spec.rb
|
274
253
|
- spec/collections/playlist_items_spec.rb
|
275
254
|
- spec/collections/playlists_spec.rb
|
276
255
|
- spec/collections/ratings_spec.rb
|
@@ -299,6 +278,21 @@ test_files:
|
|
299
278
|
- spec/models/url_spec.rb
|
300
279
|
- spec/models/user_info_spec.rb
|
301
280
|
- spec/models/video_spec.rb
|
281
|
+
- spec/requests/as_account/account_spec.rb
|
282
|
+
- spec/requests/as_account/authentications_spec.rb
|
283
|
+
- spec/requests/as_account/channel_spec.rb
|
284
|
+
- spec/requests/as_account/playlist_item_spec.rb
|
285
|
+
- spec/requests/as_account/playlist_spec.rb
|
286
|
+
- spec/requests/as_account/resource_spec.rb
|
287
|
+
- spec/requests/as_account/video_spec.rb
|
288
|
+
- spec/requests/as_content_owner/channel_spec.rb
|
289
|
+
- spec/requests/as_content_owner/content_owner_spec.rb
|
290
|
+
- spec/requests/as_server_app/channel_spec.rb
|
291
|
+
- spec/requests/as_server_app/playlist_item_spec.rb
|
292
|
+
- spec/requests/as_server_app/playlist_spec.rb
|
293
|
+
- spec/requests/as_server_app/resource_spec.rb
|
294
|
+
- spec/requests/as_server_app/video_spec.rb
|
295
|
+
- spec/requests/unauthenticated/video_spec.rb
|
302
296
|
- spec/spec_helper.rb
|
303
297
|
- spec/support/fail_matcher.rb
|
304
298
|
- spec/support/global_hooks.rb
|
@@ -1,44 +0,0 @@
|
|
1
|
-
require 'yt/collections/earnings'
|
2
|
-
|
3
|
-
module Yt
|
4
|
-
module Associations
|
5
|
-
# Provides methods which allows to access the earnings generated by a resource.
|
6
|
-
#
|
7
|
-
# YouTube resources with earning are: {Yt::Models::Channel channels}.
|
8
|
-
module Earnings
|
9
|
-
# @return [Float] the estimated earnings for one specific day in USD.
|
10
|
-
# @param [Date or Time or DateTime or String] date The date to obtain
|
11
|
-
# the estimated earnings for. If +String+, must be Date-parseable.
|
12
|
-
def earnings_on(date)
|
13
|
-
earnings(from: date, to: date).values.first
|
14
|
-
end
|
15
|
-
|
16
|
-
# @return [Hash] the estimated earnings for a range of days. Each +key+ is a +Date+
|
17
|
-
# and each +value+ is a +Float+, representing estimated earnings in USD.
|
18
|
-
# @param [Hash] options the range of days to get the earnings for.
|
19
|
-
# @option options [Date or Time or DateTime or String] :since The start
|
20
|
-
# of the days range. If +String+, must be Date-parseable. Also aliased as *:from*.
|
21
|
-
# @option options [Date or Time or DateTime or String] :until The end
|
22
|
-
# of the days range. If +String+, must be Date-parseable. Also aliased as *:to*.
|
23
|
-
def earnings(options = {})
|
24
|
-
from = options[:since] || options[:from] || 6.days.ago
|
25
|
-
to = options[:until] || options[:to] || 2.days.ago
|
26
|
-
range = Range.new *[from, to].map(&:to_date)
|
27
|
-
|
28
|
-
Hash[*range.flat_map do |date|
|
29
|
-
[date, (@earnings ||= {})[date] ||= range_earnings(range)[date]]
|
30
|
-
end]
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def range_earnings(date_range)
|
36
|
-
(@range_earnings ||= {})[date_range] ||= all_earnings.within date_range
|
37
|
-
end
|
38
|
-
|
39
|
-
def all_earnings
|
40
|
-
Collections::Earnings.of self
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
require 'yt/collections/views'
|
2
|
-
|
3
|
-
module Yt
|
4
|
-
module Associations
|
5
|
-
# Provides methods which allows to access the view count of a resource.
|
6
|
-
#
|
7
|
-
# YouTube resources with view counts are: {Yt::Models::Channel channels}.
|
8
|
-
module Views
|
9
|
-
# @return [Integer, nil] the view count for one specific day.
|
10
|
-
# @param [Date or Time or DateTime or String] date The date to obtain
|
11
|
-
# the views for. If +String+, must be Date-parseable.
|
12
|
-
def views_on(date)
|
13
|
-
views(from: date, to: date).values.first
|
14
|
-
end
|
15
|
-
|
16
|
-
# @return [Hash] the view counts for a range of days. Each +key+ is a +Date+
|
17
|
-
# and each +value+ is an +Integer+ or +nil+, representing the number of views.
|
18
|
-
# @param [Hash] options the range of days to get the view for.
|
19
|
-
# @option options [Date or Time or DateTime or String] :since The start
|
20
|
-
# of the days range. If +String+, must be Date-parseable. Also aliased as *:from*.
|
21
|
-
# @option options [Date or Time or DateTime or String] :until The end
|
22
|
-
# of the days range. If +String+, must be Date-parseable. Also aliased as *:to*.
|
23
|
-
def views(options = {})
|
24
|
-
from = options[:since] || options[:from] || 5.days.ago
|
25
|
-
to = options[:until] || options[:to] || 1.day.ago
|
26
|
-
range = Range.new *[from, to].map(&:to_date)
|
27
|
-
|
28
|
-
Hash[*range.flat_map do |date|
|
29
|
-
[date, (@views ||= {})[date] ||= range_views(range)[date]]
|
30
|
-
end]
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def range_views(date_range)
|
36
|
-
(@range_views ||= {})[date_range] ||= all_views.within date_range
|
37
|
-
end
|
38
|
-
|
39
|
-
def all_views
|
40
|
-
Collections::Views.of self
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
data/lib/yt/collections/views.rb
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
|
-
describe Yt::Associations::Earnings, :partner do
|
6
|
-
context 'given a partnered channel' do
|
7
|
-
let(:channel) { Yt::Channel.new id: channel_id, auth: $content_owner }
|
8
|
-
|
9
|
-
context 'managed by the authenticated Content Owner' do
|
10
|
-
let(:channel_id) { ENV['YT_TEST_PARTNER_CHANNEL_ID'] }
|
11
|
-
|
12
|
-
describe '#earnings_on' do
|
13
|
-
context 'and a date in which the channel made any money' do
|
14
|
-
let(:earnings) { channel.earnings_on 5.days.ago}
|
15
|
-
it { expect(earnings).to be_a Float }
|
16
|
-
end
|
17
|
-
|
18
|
-
# NOTE: This test sounds redundant, but it’s actually a reflection of
|
19
|
-
# another irrational behavior of YouTube API. In short, if you ask for
|
20
|
-
# the "earnings" metric of a day in which a channel made 0 USD, then
|
21
|
-
# the API returns "nil". But if you also for the "earnings" metric AND
|
22
|
-
# the "estimatedMinutesWatched" metric, then the API returns the
|
23
|
-
# correct value of "0", while still returning nil for those days in
|
24
|
-
# which the earnings have not been estimated yet.
|
25
|
-
context 'and a date in which the channel did not make any money' do
|
26
|
-
let(:zero_date) { ENV['YT_TEST_PARTNER_CHANNEL_NO_EARNINGS_DATE'] }
|
27
|
-
let(:earnings) { channel.earnings_on zero_date}
|
28
|
-
it { expect(earnings).to eq 0 }
|
29
|
-
end
|
30
|
-
|
31
|
-
context 'and a date for which earnings have not yet been estimated' do
|
32
|
-
let(:earnings) { channel.earnings_on 5.days.from_now}
|
33
|
-
it { expect(earnings).to be_nil }
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
describe '#earnings' do
|
38
|
-
let(:date) { 4.days.ago }
|
39
|
-
|
40
|
-
context 'given a :since option' do
|
41
|
-
let(:earnings) { channel.earnings since: date}
|
42
|
-
it { expect(earnings.keys.min).to eq date.to_date }
|
43
|
-
end
|
44
|
-
|
45
|
-
context 'given a :from option' do
|
46
|
-
let(:earnings) { channel.earnings from: date}
|
47
|
-
it { expect(earnings.keys.min).to eq date.to_date }
|
48
|
-
end
|
49
|
-
|
50
|
-
context 'given a :until option' do
|
51
|
-
let(:earnings) { channel.earnings until: date}
|
52
|
-
it { expect(earnings.keys.max).to eq date.to_date }
|
53
|
-
end
|
54
|
-
|
55
|
-
context 'given a :to option' do
|
56
|
-
let(:earnings) { channel.earnings to: date}
|
57
|
-
it { expect(earnings.keys.max).to eq date.to_date }
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
context 'not managed by the authenticated Content Owner' do
|
63
|
-
let(:channel_id) { 'UCBR8-60-B28hp2BmDPdntcQ' }
|
64
|
-
it { expect{channel.earnings}.to raise_error Yt::Errors::Forbidden }
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
@@ -1,52 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Yt::Associations::Views, :partner do
|
4
|
-
context 'given a partnered channel' do
|
5
|
-
let(:channel) { Yt::Channel.new id: channel_id, auth: $content_owner }
|
6
|
-
|
7
|
-
context 'managed by the authenticated Content Owner' do
|
8
|
-
let(:channel_id) { ENV['YT_TEST_PARTNER_CHANNEL_ID'] }
|
9
|
-
|
10
|
-
describe '#views_on' do
|
11
|
-
context 'and a date in which the channel was partnered' do
|
12
|
-
let(:views) { channel.views_on 5.days.ago}
|
13
|
-
it { expect(views).to be_an Integer }
|
14
|
-
end
|
15
|
-
|
16
|
-
context 'and a date in which the channel was not partnered' do
|
17
|
-
let(:views) { channel.views_on 20.years.ago}
|
18
|
-
it { expect(views).to be_nil }
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
describe '#views' do
|
23
|
-
let(:date) { 4.days.ago }
|
24
|
-
|
25
|
-
context 'given a :since option' do
|
26
|
-
let(:views) { channel.views since: date}
|
27
|
-
it { expect(views.keys.min).to eq date.to_date }
|
28
|
-
end
|
29
|
-
|
30
|
-
context 'given a :from option' do
|
31
|
-
let(:views) { channel.views from: date}
|
32
|
-
it { expect(views.keys.min).to eq date.to_date }
|
33
|
-
end
|
34
|
-
|
35
|
-
context 'given a :until option' do
|
36
|
-
let(:views) { channel.views until: date}
|
37
|
-
it { expect(views.keys.max).to eq date.to_date }
|
38
|
-
end
|
39
|
-
|
40
|
-
context 'given a :to option' do
|
41
|
-
let(:views) { channel.views to: date}
|
42
|
-
it { expect(views.keys.max).to eq date.to_date }
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
context 'not managed by the authenticated Content Owner' do
|
48
|
-
let(:channel_id) { 'UCBR8-60-B28hp2BmDPdntcQ' }
|
49
|
-
it { expect{channel.views}.to raise_error Yt::Errors::Forbidden }
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'yt/collections/earnings'
|
3
|
-
|
4
|
-
describe Yt::Collections::Earnings do
|
5
|
-
subject(:collection) { Yt::Collections::Earnings.new parent: channel }
|
6
|
-
let(:channel) { Yt::Channel.new id: 'UCxO1tY8h1AhOz0T4ENwmpow' }
|
7
|
-
let(:date) { 1.day.ago.to_date }
|
8
|
-
let(:dollars) { 10 }
|
9
|
-
before { expect(collection).to behave }
|
10
|
-
|
11
|
-
describe '#within' do
|
12
|
-
context 'given YouTube responds with a list of earnings' do
|
13
|
-
let(:behave) { receive(:flat_map).and_return [date, dollars] }
|
14
|
-
|
15
|
-
it { expect(collection.within(date..date)[date]).to eq dollars }
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|