From 090e9fcb9732a6c45dc3839d63b8c08dbac4af91 Mon Sep 17 00:00:00 2001 From: claudiob Date: Thu, 29 May 2014 17:22:13 -0700 Subject: [PATCH] @wip Implementing analytics --- lib/yt.rb | 3 ++- lib/yt/actions/list.rb | 8 +++++-- lib/yt/associations.rb | 1 + lib/yt/associations/earnings.rb | 36 ++++++++++++++++++++++++++++ lib/yt/collections/earnings.rb | 42 +++++++++++++++++++++++++++++++++ lib/yt/models/account.rb | 18 ++------------ lib/yt/models/authenticable.rb | 22 +++++++++++++++++ lib/yt/models/channel.rb | 1 + lib/yt/models/content_owner.rb | 15 ++++++++++++ 9 files changed, 127 insertions(+), 19 deletions(-) create mode 100644 lib/yt/associations/earnings.rb create mode 100644 lib/yt/collections/earnings.rb create mode 100644 lib/yt/models/authenticable.rb create mode 100644 lib/yt/models/content_owner.rb diff --git a/lib/yt.rb b/lib/yt.rb index 38208bd9..679b2b18 100644 --- a/lib/yt.rb +++ b/lib/yt.rb @@ -1,2 +1,3 @@ require 'yt/config' -require 'yt/models/account' \ No newline at end of file +require 'yt/models/account' +require 'yt/models/content_owner' \ No newline at end of file diff --git a/lib/yt/actions/list.rb b/lib/yt/actions/list.rb index f192948b..97ace6f6 100644 --- a/lib/yt/actions/list.rb +++ b/lib/yt/actions/list.rb @@ -4,7 +4,7 @@ module Yt module Actions module List - delegate :count, :first, :any?, :each, :map, :find, to: :list + delegate :count, :first, :any?, :each, :map, :flat_map, :find, to: :list alias size count def first! @@ -51,7 +51,7 @@ def fetch_page(params = {}) request = Yt::Request.new params response = request.run token = response.body['nextPageToken'] - items = response.body.fetch 'items', [] + items = response.body.fetch items_key, [] {items: items, token: token} end @@ -65,6 +65,10 @@ def list_params params[:exptected_response] = Net::HTTPOK end end + + def items_key + 'items' + end end end end \ No newline at end of file diff --git a/lib/yt/associations.rb b/lib/yt/associations.rb index a0591ea8..1264c025 100644 --- a/lib/yt/associations.rb +++ b/lib/yt/associations.rb @@ -14,6 +14,7 @@ module Associations autoload :Authentications autoload :Channels autoload :DetailsSets + autoload :Earnings autoload :Ids autoload :PlaylistItems autoload :Playlists diff --git a/lib/yt/associations/earnings.rb b/lib/yt/associations/earnings.rb new file mode 100644 index 00000000..ba189150 --- /dev/null +++ b/lib/yt/associations/earnings.rb @@ -0,0 +1,36 @@ +require 'yt/collections/earnings' + +module Yt + module Associations + # Provides the `has_many :earnings` method to YouTube resources, which + # allows to invoke earning-related methods, such as .earnings_on. + # YouTube resources with earning are: channels. + module Earnings + def earnings_on(date) + earnings_within(date, date).values.first + end + + def earnings_since(from) + # NOTE: Today's earnings are not available, and hardly yesterday's + earnings_within from, 1.day.ago + end + + def earnings_within(from, to) + date_range = Range.new *[from, to].map(&:to_date) + Hash[*date_range.flat_map do |date| + [date, (@earnings ||= {})[date] ||= range_earnings(date_range)[date]] + end] + end + + private + + def range_earnings(date_range) + (@range_earnings ||= {})[date_range] ||= earnings.within date_range + end + + def earnings + Collections::Earnings.of self + end + end + end +end \ No newline at end of file diff --git a/lib/yt/collections/earnings.rb b/lib/yt/collections/earnings.rb new file mode 100644 index 00000000..09dc903c --- /dev/null +++ b/lib/yt/collections/earnings.rb @@ -0,0 +1,42 @@ +require 'yt/collections/base' + +module Yt + module Collections + class Earnings < Base + + def within(days_range) + @days_range = sorted days_range + Hash[*flat_map{|daily_earning| daily_earning}] + end + + private + + def new_item(data) + # NOTE: could use column headers to be more precise + [Date.iso8601(data.first), data.last] + end + + def list_params + super.tap do |params| + params[:path] = '/youtube/analytics/v1/reports' + params[:params] = {}.tap do |params| + params['ids'] = "contentOwner==#{@auth.id}" + params['filters'] = "channel==#{@parent.id}" + params['start-date'] = @days_range.begin + params['end-date'] = @days_range.end + params['metrics'] = :earnings + params['dimensions'] = :day + end + end + end + + def items_key + 'rows' + end + + def sorted(range) + range.min ? range : (range.end..range.begin) + end + end + end +end \ No newline at end of file diff --git a/lib/yt/models/account.rb b/lib/yt/models/account.rb index 473ad734..a554d03a 100644 --- a/lib/yt/models/account.rb +++ b/lib/yt/models/account.rb @@ -1,25 +1,11 @@ -require 'yt/models/base' +require 'yt/models/authenticable' module Yt module Models # Provides methods to access a YouTube account. - class Account < Base - has_one :authentication, delegate: [:access_token, :refresh_token, :expires_at] + class Account < Authenticable has_one :channel, delegate: [:videos, :playlists, :create_playlist, :delete_playlists, :update_playlists] has_one :user_info, delegate: [:id, :email, :has_verified_email?, :gender, :name, :given_name, :family_name, :profile_url, :avatar_url, :locale, :hd] - - def initialize(options = {}) - @access_token = options[:access_token] - @refresh_token = options[:refresh_token] - @expires_at = options[:expires_at] - @authorization_code = options[:authorization_code] - @redirect_uri = options[:redirect_uri] - @scopes = options[:scopes] - end - - def auth - self - end end end end \ No newline at end of file diff --git a/lib/yt/models/authenticable.rb b/lib/yt/models/authenticable.rb new file mode 100644 index 00000000..62cf4a88 --- /dev/null +++ b/lib/yt/models/authenticable.rb @@ -0,0 +1,22 @@ +require 'yt/models/base' + +module Yt + module Models + class Authenticable < Base + has_one :authentication, delegate: [:access_token, :refresh_token, :expires_at] + + def initialize(options = {}) + @access_token = options[:access_token] + @refresh_token = options[:refresh_token] + @expires_at = options[:expires_at] + @authorization_code = options[:authorization_code] + @redirect_uri = options[:redirect_uri] + @scopes = options[:scopes] + end + + def auth + self + end + end + end +end \ No newline at end of file diff --git a/lib/yt/models/channel.rb b/lib/yt/models/channel.rb index 0d03edf3..f33e7aa9 100644 --- a/lib/yt/models/channel.rb +++ b/lib/yt/models/channel.rb @@ -6,6 +6,7 @@ class Channel < Resource has_many :subscriptions has_many :videos has_many :playlists + has_many :earnings # requires auth with an account with 'yt-analytics-monetary.readonly' end end end \ No newline at end of file diff --git a/lib/yt/models/content_owner.rb b/lib/yt/models/content_owner.rb new file mode 100644 index 00000000..6100a0ea --- /dev/null +++ b/lib/yt/models/content_owner.rb @@ -0,0 +1,15 @@ +require 'yt/models/authenticable' + +module Yt + module Models + # Provides methods to access a YouTube content_owner. + class ContentOwner < Authenticable + attr_reader :id + + def initialize(options = {}) + @id = options[:id] + super options + end + end + end +end \ No newline at end of file