Skip to content

Commit

Permalink
Merge pull request #26 from Fullscreen/add-viewer-percentages
Browse files Browse the repository at this point in the history
Add viewer percentages
  • Loading branch information
claudiofullscreen committed Jul 18, 2014
2 parents 05b9b63 + 535cca2 commit b11185f
Show file tree
Hide file tree
Showing 17 changed files with 157 additions and 13 deletions.
1 change: 1 addition & 0 deletions .yardopts
@@ -1,3 +1,4 @@
--no-private
lib/yt/associations/has_reports.rb
lib/yt/associations/has_viewer_percentages.rb
lib/**/*.rb
2 changes: 1 addition & 1 deletion Gemfile.lock
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
yt (0.7.9)
yt (0.7.10)
activesupport

GEM
Expand Down
1 change: 1 addition & 0 deletions HISTORY.md
Expand Up @@ -16,6 +16,7 @@ v0.7 - 2014/06/18
* Make reports available also on Video (not just Channel)
* New account.upload_video to upload a video (either local or remote).
* Make channel.videos access more than 500 videos per channel
* Add viewer percentage (age group, gender) to Channel and Video reports

v0.6 - 2014/06/05
-----------------
Expand Down
14 changes: 12 additions & 2 deletions README.md
Expand Up @@ -41,7 +41,7 @@ To install on your system, run

To use inside a bundled Ruby project, add this line to the Gemfile:

gem 'yt', '~> 0.7.9'
gem 'yt', '~> 0.7.10'

Since the gem follows [Semantic Versioning](http://semver.org),
indicating the full version in your Gemfile (~> *major*.*minor*.*patch*)
Expand Down Expand Up @@ -107,6 +107,7 @@ Use [Yt::Channel](http://rubydoc.info/github/Fullscreen/yt/master/Yt/Models/Chan
* subscribe to and unsubscribe from a channel
* create and delete playlists from a channel
* retrieve the daily earnings, views, comments, likes, dislikes, shares and impressions of a channel
* retrieve the viewer percentage of a channel by gender and age group

```ruby
channel = Yt::Channel.new id: 'UCxO1tY8h1AhOz0T4ENwmpow'
Expand Down Expand Up @@ -155,6 +156,8 @@ channel.comments until: 2.days.ago #=> {Wed, 28 May 2014 => 9.0, Thu, 29 May 201
channel.likes from: 8.days.ago #=> {Tue, 27 May 2014 => 7.0, Wed, 28 May 2014 => 0.0, …}
channel.dislikes to: 2.days.ago #=> {Tue, 27 May 2014 => 0.0, Wed, 28 May 2014 => 1.0, …}
channel.shares since: 7.days.ago, until: 7.days.ago #=> {Wed, 28 May 2014 => 3.0}

channel.viewer_percentages #=> {female: {'18-24' => 12.12, '25-34' => 16.16,…}…}
```

*The methods above require to be authenticated as the channel’s account (see below).*
Expand All @@ -170,6 +173,8 @@ channel.likes from: 8.days.ago #=> {Tue, 27 May 2014 => 7.0, Wed, 28 May 2014 =>
channel.dislikes to: 2.days.ago #=> {Tue, 27 May 2014 => 0.0, Wed, 28 May 2014 => 1.0, …}
channel.shares since: 7.days.ago, until: 7.days.ago #=> {Wed, 28 May 2014 => 3.0}
channel.impressions_on 5.days.ago #=> 157.0

channel.viewer_percentages #=> {female: {'18-24' => 12.12, '25-34' => 16.16,…}…}
```

*The methods above require to be authenticated as the channel’s content owner (see below).*
Expand All @@ -183,7 +188,8 @@ Use [Yt::Video](http://rubydoc.info/github/Fullscreen/yt/master/Yt/Models/Video)
* update the attributes of a video
* access the annotations of a video
* like and dislike a video
* retrieve the daily earnings, views, comments, likes, dislikes, shares and impressions of a channel
* retrieve the daily earnings, views, comments, likes, dislikes, shares and impressions of a video
* retrieve the viewer percentage of a video by gender and age group

```ruby
video = Yt::Video.new id: 'MESycYJytkU'
Expand Down Expand Up @@ -233,6 +239,8 @@ video.comments until: 2.days.ago #=> {Wed, 28 May 2014 => 9.0, Thu, 29 May 2014
video.likes from: 8.days.ago #=> {Tue, 27 May 2014 => 7.0, Wed, 28 May 2014 => 0.0, …}
video.dislikes to: 2.days.ago #=> {Tue, 27 May 2014 => 0.0, Wed, 28 May 2014 => 1.0, …}
video.shares since: 7.days.ago, until: 7.days.ago #=> {Wed, 28 May 2014 => 3.0}

video.viewer_percentages #=> {female: {'18-24' => 12.12, '25-34' => 16.16,…}…}
```

*The methods above require to be authenticated as the video’s owner (see below).*
Expand All @@ -248,6 +256,8 @@ video.likes from: 8.days.ago #=> {Tue, 27 May 2014 => 7.0, Wed, 28 May 2014 => 0
video.dislikes to: 2.days.ago #=> {Tue, 27 May 2014 => 0.0, Wed, 28 May 2014 => 1.0, …}
video.shares since: 7.days.ago, until: 7.days.ago #=> {Wed, 28 May 2014 => 3.0}
video.impressions_on 5.days.ago #=> 157.0

video.viewer_percentages #=> {female: {'18-24' => 12.12, '25-34' => 16.16,…}…}
```

*The methods above require to be authenticated as the video’s content owner (see below).*
Expand Down
2 changes: 2 additions & 0 deletions bin/yt
Expand Up @@ -53,6 +53,7 @@ puts " Subscribers are visible? #{channel.subscriber_count_visible?}"
# puts " Likes: #{channel.likes}"
# puts " Dislikes: #{channel.dislikes}"
# puts " Shares: #{channel.shares}"
# puts " Viewers: #{channel.viewer_percentages}"

account.videos.first(5).each.with_index do |video, i|
puts "\nVIDEO #{i+1}:\n"
Expand Down Expand Up @@ -82,6 +83,7 @@ account.videos.first(5).each.with_index do |video, i|
# puts " Likes: #{video.likes}"
# puts " Dislikes: #{video.dislikes}"
# puts " Shares: #{video.shares}"
# puts " Viewers: #{video.viewer_percentages}"
puts " Annotations: #{video.annotations.count}"
end

Expand Down
4 changes: 2 additions & 2 deletions lib/yt/associations/has_reports.rb
@@ -1,9 +1,9 @@
module Yt
module Associations
# Provides methods to to access the analytics reports of a resource.
# Provides methods to access the analytics reports of a resource.
#
# YouTube resources with reports are: {Yt::Models::Channel channels} and
# {Yt::Models::Channel videos}.
# {Yt::Models::Channel videos}.
module HasReports
# @!macro has_report
# @!method $1_on(date)
Expand Down
39 changes: 39 additions & 0 deletions lib/yt/associations/has_viewer_percentages.rb
@@ -0,0 +1,39 @@
module Yt
module Associations
# Provides methods to access the viewer percentage reports of a resource.
#
# YouTube resources with viewer percentage reports are:
# {Yt::Models::Channel channels} and {Yt::Models::Channel videos}.
module HasViewerPercentages
# @!macro has_viewer_percentages
# @!method viewer_percentages
# @return [Hash<Symbol,Hash<String,Float>>] the viewer percentages.
# The first-level hash identifies the genres (:female, :male).
# The second-level hash identifies the age ranges ('18-24',
# '25-34', '35-44', '45-54', '55-64', '65-')
# @example Return the % of male viewers of a channel older than 64
# channel.viewer_percentages[:male]['65-'] #=> 12.02

# Defines a public instance methods to access the viewer percentages of
# a resource for a specific metric.
# @example Adds +viewer_percentages+ on a Channel resource.
# class Channel < Resource
# has_viewer_percentages
# end
def has_viewer_percentages
require 'yt/collections/viewer_percentages'

define_viewer_percentages_method
end

private

def define_viewer_percentages_method
# @todo: add options like start and end date
define_method :viewer_percentages do
@viewer_percentages ||= Collections::ViewerPercentages.of(self).all
end
end
end
end
end
10 changes: 5 additions & 5 deletions lib/yt/collections/resumable_sessions.rb
Expand Up @@ -14,11 +14,11 @@ class ResumableSessions < Base
# video to upload. If the request succeeds, YouTube returns a unique
# URL to upload the video file (and eventually resume the upload).
# @param [Integer] content_length the size (bytes) of the video to upload.
# @param [Hash] params the metadata to add to the uploaded video.
# @option params [String] :title The video’s title.
# @option params [String] :description The video’s description.
# @option params [Array<String>] :title The video’s tags.
# @option params [String] :privacy_status The video’s privacy status.
# @param [Hash] options the metadata to add to the uploaded video.
# @option options [String] :title The video’s title.
# @option options [String] :description The video’s description.
# @option options [Array<String>] :title The video’s tags.
# @option options [String] :privacy_status The video’s privacy status.
def insert(content_length, options = {})
@headers = headers_for content_length
body = {}
Expand Down
46 changes: 46 additions & 0 deletions lib/yt/collections/viewer_percentages.rb
@@ -0,0 +1,46 @@
require 'yt/collections/base'

module Yt
module Collections
class ViewerPercentages < Base

def all
Hash.new{|h,k| h[k] = Hash.new(0.0)}.tap do |hash|
each{|item| hash[item.gender][item.age_range] = item.value}
end
end

private

# @note could use column headers to be more precise
def new_item(data)
Struct.new(:gender, :age_range, :value).new.tap do |item|
item.gender = data.first.to_sym
item.age_range = data.second.gsub /^age/, ''
item.value = data.last
end
end

def list_params
super.tap do |params|
params[:path] = '/youtube/analytics/v1/reports'
params[:params] = @parent.reports_params.merge reports_params
end
end

def reports_params
{}.tap do |params|
params['start-date'] = 3.months.ago.to_date
params['end-date'] = Date.today.to_date
params['metrics'] = :viewerPercentage
params['dimensions'] = 'gender,ageGroup'
params['sort'] = 'gender,ageGroup'
end
end

def items_key
'rows'
end
end
end
end
2 changes: 2 additions & 0 deletions lib/yt/models/base.rb
Expand Up @@ -5,6 +5,7 @@
require 'yt/associations/has_many'
require 'yt/associations/has_one'
require 'yt/associations/has_reports'
require 'yt/associations/has_viewer_percentages'

require 'yt/errors/request_error'

Expand All @@ -15,6 +16,7 @@ class Base
include Actions::Update

extend Associations::HasReports
extend Associations::HasViewerPercentages
extend Associations::HasOne
extend Associations::HasMany
extend Associations::HasAuthentication
Expand Down
3 changes: 3 additions & 0 deletions lib/yt/models/channel.rb
Expand Up @@ -38,6 +38,9 @@ class Channel < Resource
# @macro has_report
has_report :impressions

# @macro has_viewer_percentages
has_viewer_percentages

# @!attribute [r] statistics_set
# @return [Yt::Models::StatisticsSet] the statistics for the video.
has_one :statistics_set
Expand Down
3 changes: 3 additions & 0 deletions lib/yt/models/video.rb
Expand Up @@ -43,6 +43,9 @@ class Video < Resource
# @macro has_report
has_report :impressions

# @macro has_viewer_percentages
has_viewer_percentages

# @!attribute [r] statistics_set
# @return [Yt::Models::StatisticsSet] the statistics for the video.
has_one :statistics_set
Expand Down
2 changes: 1 addition & 1 deletion lib/yt/version.rb
@@ -1,3 +1,3 @@
module Yt
VERSION = '0.7.9'
VERSION = '0.7.10'
end
4 changes: 4 additions & 0 deletions spec/requests/as_account/channel_spec.rb
Expand Up @@ -99,6 +99,10 @@
expect{channel.earnings_on 3.days.ago}.to raise_error Yt::Errors::Unauthorized
expect{channel.impressions_on 3.days.ago}.to raise_error Yt::Errors::Unauthorized
end

it 'returns valid reports for channel-related demographics' do
expect{channel.viewer_percentages}.not_to raise_error
end
end

context 'given an unknown channel' do
Expand Down
7 changes: 5 additions & 2 deletions spec/requests/as_account/video_spec.rb
Expand Up @@ -79,8 +79,7 @@
it { expect{video.update attrs}.not_to change{video.privacy_status} }
end


it 'returns valid reports for channel-related metrics' do
it 'returns valid reports for video-related metrics' do
# Some reports are only available to Content Owners.
# See content ownere test for more details about what the methods return.
expect{video.views}.not_to raise_error
Expand All @@ -99,5 +98,9 @@
expect{video.earnings_on 3.days.ago}.to raise_error Yt::Errors::Unauthorized
expect{video.impressions_on 3.days.ago}.to raise_error Yt::Errors::Unauthorized
end

it 'returns valid reports for video-related demographics' do
expect{video.viewer_percentages}.not_to raise_error
end
end
end
15 changes: 15 additions & 0 deletions spec/requests/as_content_owner/channel_spec.rb
Expand Up @@ -245,6 +245,21 @@
expect(channel.impressions(to: date).keys.max).to eq date.to_date
end
end

specify 'viewer percentages by gender and age range can be retrieved' do
expect(channel.viewer_percentages[:female]['18-24']).to be_a Float
expect(channel.viewer_percentages[:female]['25-34']).to be_a Float
expect(channel.viewer_percentages[:female]['35-44']).to be_a Float
expect(channel.viewer_percentages[:female]['45-54']).to be_a Float
expect(channel.viewer_percentages[:female]['55-64']).to be_a Float
expect(channel.viewer_percentages[:female]['65-']).to be_a Float
expect(channel.viewer_percentages[:male]['18-24']).to be_a Float
expect(channel.viewer_percentages[:male]['25-34']).to be_a Float
expect(channel.viewer_percentages[:male]['35-44']).to be_a Float
expect(channel.viewer_percentages[:male]['45-54']).to be_a Float
expect(channel.viewer_percentages[:male]['55-64']).to be_a Float
expect(channel.viewer_percentages[:male]['65-']).to be_a Float
end
end

context 'not managed by the authenticated Content Owner' do
Expand Down
15 changes: 15 additions & 0 deletions spec/requests/as_content_owner/video_spec.rb
Expand Up @@ -232,6 +232,21 @@
expect(video.impressions(to: date).keys.max).to eq date.to_date
end
end

specify 'viewer percentages by gender and age range can be retrieved' do
expect(video.viewer_percentages[:female]['18-24']).to be_a Float
expect(video.viewer_percentages[:female]['25-34']).to be_a Float
expect(video.viewer_percentages[:female]['35-44']).to be_a Float
expect(video.viewer_percentages[:female]['45-54']).to be_a Float
expect(video.viewer_percentages[:female]['55-64']).to be_a Float
expect(video.viewer_percentages[:female]['65-']).to be_a Float
expect(video.viewer_percentages[:male]['18-24']).to be_a Float
expect(video.viewer_percentages[:male]['25-34']).to be_a Float
expect(video.viewer_percentages[:male]['35-44']).to be_a Float
expect(video.viewer_percentages[:male]['45-54']).to be_a Float
expect(video.viewer_percentages[:male]['55-64']).to be_a Float
expect(video.viewer_percentages[:male]['65-']).to be_a Float
end
end
end
end

0 comments on commit b11185f

Please sign in to comment.