yt 0.5.14 → 0.6.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/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
|