yt 0.5.14 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/HISTORY.md +6 -0
- data/README.md +5 -2
- data/lib/yt/associations.rb +1 -0
- data/lib/yt/associations/earnings.rb +5 -5
- data/lib/yt/associations/views.rb +52 -0
- data/lib/yt/collections/views.rb +38 -0
- data/lib/yt/models/channel.rb +2 -1
- data/lib/yt/version.rb +1 -1
- data/spec/associations/device_auth/earnings_spec.rb +9 -9
- data/spec/associations/device_auth/views_spec.rb +52 -0
- metadata +5 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 21b5af2314c676c2ba25c60e8b5f9162cb2692f1
|
4
|
+
data.tar.gz: 3b9b42304e0f418b5b95830171dfddecc53dccb1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c61d1a02c65e1409c0ee6959a131027919962dd91255378e95eb3b7c6d4940fe92c6c999c161aee7d69a1abdc20e6bd1e7b3d619fbe1e423e651e4fcb0c5847
|
7
|
+
data.tar.gz: 50a18ac7b664828653834e7aa5464376bd3ffd89cc4870fd64640a7a47d265522f8bdc17d6d5d80c80b88412c06e9b57db0b18bfa6e0cca5a8055cefcaaf5bda
|
data/Gemfile.lock
CHANGED
data/HISTORY.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
v0.6 - 2014/06/05
|
2
|
+
-----------------
|
3
|
+
|
4
|
+
* [breaking change] Rename Channel#earning to Channel#earnings_on
|
5
|
+
|
1
6
|
v0.5 - 2014/05/16
|
2
7
|
-----------------
|
3
8
|
|
@@ -20,6 +25,7 @@ v0.5 - 2014/05/16
|
|
20
25
|
* Automatically refresh the access token when it expires or becomes invalid
|
21
26
|
* Retry once YouTube earning queries that return error 503
|
22
27
|
* Wait 3 seconds and retry *every* request that returns 500, 503 or 400 with "Invalid query"
|
28
|
+
* New Views collection to retrieve view count for YouTube-partnered channels
|
23
29
|
|
24
30
|
v0.4 - 2014/05/09
|
25
31
|
--------------------
|
data/README.md
CHANGED
@@ -112,8 +112,11 @@ channel.delete_playlists title: 'New playlist' #=> [true]
|
|
112
112
|
content_owner = Yt::ContentOwner.new owner_name: 'CMSname', access_token: 'ya29.1.ABCDEFGHIJ'
|
113
113
|
channel = Yt::Channel.new id: 'UCxO1tY8h1AhOz0T4ENwmpow', auth: content_owner
|
114
114
|
|
115
|
-
channel.
|
115
|
+
channel.earnings_on 5.days.ago #=> 12.23
|
116
116
|
channel.earnings since: 3.days.ago, until: 2.days.ago #=> {Wed, 28 May 2014 => 1.34, Thu, 29 May 2014 => 0.47}
|
117
|
+
|
118
|
+
channel.views_on 5.days.ago #=> 44
|
119
|
+
channel.views since: 3.days.ago, until: 2.days.ago #=> {Wed, 28 May 2014 => 12, Thu, 29 May 2014 => 3}
|
117
120
|
```
|
118
121
|
|
119
122
|
*The methods above require to be authenticated as the channel’s content owner (see below).*
|
@@ -323,7 +326,7 @@ To install on your system, run
|
|
323
326
|
|
324
327
|
To use inside a bundled Ruby project, add this line to the Gemfile:
|
325
328
|
|
326
|
-
gem 'yt', '~> 0.
|
329
|
+
gem 'yt', '~> 0.6.0'
|
327
330
|
|
328
331
|
Since the gem follows [Semantic Versioning](http://semver.org),
|
329
332
|
indicating the full version in your Gemfile (~> *major*.*minor*.*patch*)
|
data/lib/yt/associations.rb
CHANGED
@@ -6,17 +6,17 @@ module Yt
|
|
6
6
|
# allows to invoke earning-related methods, such as .earnings.
|
7
7
|
# YouTube resources with earning are: channels.
|
8
8
|
module Earnings
|
9
|
-
# Return the estimated
|
9
|
+
# Return the estimated earnings for one specific day.
|
10
10
|
#
|
11
11
|
# @param [Date or Time or DateTime or String] date The date to obtain
|
12
12
|
# the estimated earnings for. If String, must be Date-parseable.
|
13
13
|
#
|
14
14
|
# @return [Float] The estimated earnings in USD.
|
15
|
-
def
|
15
|
+
def earnings_on(date)
|
16
16
|
earnings(from: date, to: date).values.first
|
17
17
|
end
|
18
18
|
|
19
|
-
# Return the estimated
|
19
|
+
# Return the estimated earnings for a range of days.
|
20
20
|
#
|
21
21
|
# @param [Hash] options the range of days to get the earnings for.
|
22
22
|
# @option options [Date or Time or DateTime or String] :since The start
|
@@ -29,8 +29,8 @@ module Yt
|
|
29
29
|
# @return [Hash] The estimated earnings by day. Each :key is a Date
|
30
30
|
# and each :value is a Float, representing estimated earnings in USD.
|
31
31
|
def earnings(options = {})
|
32
|
-
from = options[:since] || options[:from] ||
|
33
|
-
to = options[:until] || options[:to] ||
|
32
|
+
from = options[:since] || options[:from] || 6.days.ago
|
33
|
+
to = options[:until] || options[:to] || 2.days.ago
|
34
34
|
range = Range.new *[from, to].map(&:to_date)
|
35
35
|
|
36
36
|
Hash[*range.flat_map do |date|
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'yt/collections/views'
|
2
|
+
|
3
|
+
module Yt
|
4
|
+
module Associations
|
5
|
+
# Provides the `has_many :views` method to YouTube resources, which
|
6
|
+
# allows to invoke view-related methods, such as .views.
|
7
|
+
# YouTube resources with views are: channels.
|
8
|
+
module Views
|
9
|
+
# Return the view count for one specific day.
|
10
|
+
#
|
11
|
+
# @param [Date or Time or DateTime or String] date The date to obtain
|
12
|
+
# the estimated views for. If String, must be Date-parseable.
|
13
|
+
#
|
14
|
+
# @return [Integer or Nil] The estimated views.
|
15
|
+
def views_on(date)
|
16
|
+
views(from: date, to: date).values.first
|
17
|
+
end
|
18
|
+
|
19
|
+
# Return the view count for a range of days.
|
20
|
+
#
|
21
|
+
# @param [Hash] options the range of days to get the views for.
|
22
|
+
# @option options [Date or Time or DateTime or String] :since The start
|
23
|
+
# of the days range. If String, must be Date-parseable.
|
24
|
+
# @note options[:since] is aliased as options[:from]
|
25
|
+
# @option options [Date or Time or DateTime or String] :until The end
|
26
|
+
# of the days range. If String, must be Date-parseable.
|
27
|
+
# @note options[:until] is aliased as options[:to]
|
28
|
+
#
|
29
|
+
# @return [Hash] The view count by day. Each :key is a Date
|
30
|
+
# and each :value is an Integer or nil, representing the number of views.
|
31
|
+
def views(options = {})
|
32
|
+
from = options[:since] || options[:from] || 5.days.ago
|
33
|
+
to = options[:until] || options[:to] || 1.day.ago
|
34
|
+
range = Range.new *[from, to].map(&:to_date)
|
35
|
+
|
36
|
+
Hash[*range.flat_map do |date|
|
37
|
+
[date, (@views ||= {})[date] ||= range_views(range)[date]]
|
38
|
+
end]
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def range_views(date_range)
|
44
|
+
(@range_views ||= {})[date_range] ||= all_views.within date_range
|
45
|
+
end
|
46
|
+
|
47
|
+
def all_views
|
48
|
+
Collections::Views.of self
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'yt/collections/base'
|
2
|
+
|
3
|
+
module Yt
|
4
|
+
module Collections
|
5
|
+
class Views < Base
|
6
|
+
|
7
|
+
def within(days_range)
|
8
|
+
@days_range = days_range
|
9
|
+
Hash[*flat_map{|daily_view| daily_view}]
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def new_item(data)
|
15
|
+
# NOTE: could use column headers to be more precise
|
16
|
+
[Date.iso8601(data.first), (data.last.to_i if data.last)]
|
17
|
+
end
|
18
|
+
|
19
|
+
def list_params
|
20
|
+
super.tap do |params|
|
21
|
+
params[:path] = '/youtube/analytics/v1/reports'
|
22
|
+
params[:params] = {}.tap do |params|
|
23
|
+
params['ids'] = "contentOwner==#{@auth.owner_name}"
|
24
|
+
params['filters'] = "channel==#{@parent.id}"
|
25
|
+
params['start-date'] = @days_range.begin
|
26
|
+
params['end-date'] = @days_range.end
|
27
|
+
params['metrics'] = :views
|
28
|
+
params['dimensions'] = :day
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def items_key
|
34
|
+
'rows'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/yt/models/channel.rb
CHANGED
data/lib/yt/version.rb
CHANGED
@@ -7,10 +7,10 @@ describe Yt::Associations::Earnings, :partner do
|
|
7
7
|
context 'managed by the authenticated Content Owner' do
|
8
8
|
let(:channel_id) { ENV['YT_TEST_PARTNER_CHANNEL_ID'] }
|
9
9
|
|
10
|
-
describe '#
|
10
|
+
describe '#earnings_on' do
|
11
11
|
context 'and a date in which the channel made any money' do
|
12
|
-
let(:
|
13
|
-
it { expect(
|
12
|
+
let(:earnings) { channel.earnings_on 5.days.ago}
|
13
|
+
it { expect(earnings).to be_a Float }
|
14
14
|
end
|
15
15
|
|
16
16
|
# NOTE: This test sounds redundant, but it’s actually a reflection of
|
@@ -22,17 +22,17 @@ describe Yt::Associations::Earnings, :partner do
|
|
22
22
|
# which the earnings have not been estimated yet.
|
23
23
|
context 'and a date in which the channel did not make any money' do
|
24
24
|
let(:zero_date) { ENV['YT_TEST_PARTNER_CHANNEL_NO_EARNINGS_DATE'] }
|
25
|
-
let(:
|
26
|
-
it { expect(
|
25
|
+
let(:earnings) { channel.earnings_on zero_date}
|
26
|
+
it { expect(earnings).to eq 0 }
|
27
27
|
end
|
28
28
|
|
29
29
|
context 'and a date for which earnings have not yet been estimated' do
|
30
|
-
let(:
|
31
|
-
it { expect(
|
30
|
+
let(:earnings) { channel.earnings_on 5.days.from_now}
|
31
|
+
it { expect(earnings).to be_nil }
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
describe '#
|
35
|
+
describe '#earnings' do
|
36
36
|
let(:date) { 4.days.ago }
|
37
37
|
|
38
38
|
context 'given a :since option' do
|
@@ -59,7 +59,7 @@ describe Yt::Associations::Earnings, :partner do
|
|
59
59
|
|
60
60
|
context 'not managed by the authenticated Content Owner' do
|
61
61
|
let(:channel_id) { 'UCBR8-60-B28hp2BmDPdntcQ' }
|
62
|
-
it { expect{channel.
|
62
|
+
it { expect{channel.earnings}.to raise_error Yt::Errors::Forbidden }
|
63
63
|
end
|
64
64
|
end
|
65
65
|
end
|
@@ -0,0 +1,52 @@
|
|
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
|
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.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Claudio Baccigalupo
|
@@ -138,6 +138,7 @@ files:
|
|
138
138
|
- lib/yt/associations/subscriptions.rb
|
139
139
|
- lib/yt/associations/user_infos.rb
|
140
140
|
- lib/yt/associations/videos.rb
|
141
|
+
- lib/yt/associations/views.rb
|
141
142
|
- lib/yt/collections/annotations.rb
|
142
143
|
- lib/yt/collections/authentications.rb
|
143
144
|
- lib/yt/collections/base.rb
|
@@ -153,6 +154,7 @@ files:
|
|
153
154
|
- lib/yt/collections/subscriptions.rb
|
154
155
|
- lib/yt/collections/user_infos.rb
|
155
156
|
- lib/yt/collections/videos.rb
|
157
|
+
- lib/yt/collections/views.rb
|
156
158
|
- lib/yt/config.rb
|
157
159
|
- lib/yt/errors/forbidden.rb
|
158
160
|
- lib/yt/errors/no_items.rb
|
@@ -194,6 +196,7 @@ files:
|
|
194
196
|
- spec/associations/device_auth/subscriptions_spec.rb
|
195
197
|
- spec/associations/device_auth/user_infos_spec.rb
|
196
198
|
- spec/associations/device_auth/videos_spec.rb
|
199
|
+
- spec/associations/device_auth/views_spec.rb
|
197
200
|
- spec/associations/no_auth/annotations_spec.rb
|
198
201
|
- spec/associations/server_auth/channels_spec.rb
|
199
202
|
- spec/associations/server_auth/details_sets_spec.rb
|
@@ -279,6 +282,7 @@ test_files:
|
|
279
282
|
- spec/associations/device_auth/subscriptions_spec.rb
|
280
283
|
- spec/associations/device_auth/user_infos_spec.rb
|
281
284
|
- spec/associations/device_auth/videos_spec.rb
|
285
|
+
- spec/associations/device_auth/views_spec.rb
|
282
286
|
- spec/associations/no_auth/annotations_spec.rb
|
283
287
|
- spec/associations/server_auth/channels_spec.rb
|
284
288
|
- spec/associations/server_auth/details_sets_spec.rb
|