class Yt::Collections::Reports

@private

Constants

DEVICE_TYPES

@see developers.google.com/youtube/analytics/v1/dimsmets/dims#Device_Dimensions

DIMENSIONS
OPERATING_SYSTEMS

@see developers.google.com/youtube/analytics/v1/dimsmets/dims#Device_Dimensions

PLAYBACK_LOCATIONS

@see developers.google.com/youtube/analytics/v1/dimsmets/dims#Playback_Location_Dimensions

SUBSCRIBED_STATUSES

@see developers.google.com/youtube/analytics/v1/dimsmets/dims#Playback_Detail_Dimensions

TRAFFIC_SOURCES

@see developers.google.com/youtube/analytics/v1/dimsmets/dims#Traffic_Source_Dimensions @note EXT_APP is also returned but it’s not in the documentation above!

YOUTUBE_PRODUCTS

@see developers.google.com/youtube/analytics/v1/dimsmets/dims#youtubeProduct

Attributes

metrics[W]

Public Instance Methods

within(days_range, country, state, dimension, videos, historical, max_retries = 3) click to toggle source
# File lib/yt/collections/reports.rb, line 120
def within(days_range, country, state, dimension, videos, historical, max_retries = 3)
  @days_range = days_range
  @country = country
  @state = state
  @dimension = dimension
  @videos = videos
  @historical = historical
  if dimension == :gender_age_group # array of array
    Hash.new{|h,k| h[k] = Hash.new 0.0}.tap do |hash|
      each{|gender, age_group, value| hash[gender][age_group[3..-1]] = value}
    end
  else
    hash = flat_map do |hashes|
      hashes.map do |metric, values|
        [metric, values.transform_values{|v| type_cast(v, @metrics[metric])}]
      end.to_h
    end
    hash = hash.inject(@metrics.transform_values{|v| {}}) do |result, hash|
      result.deep_merge hash
    end
    if dimension == :month
      hash = hash.transform_values{|h| h.sort_by{|range, v| range.first}.to_h}
    elsif dimension == :day
      hash = hash.transform_values{|h| h.sort_by{|day, v| day}.to_h}
    elsif dimension.in? [:traffic_source, :country, :state, :playback_location, :device_type, :operating_system, :subscribed_status]
      hash = hash.transform_values{|h| h.sort_by{|range, v| -v}.to_h}
    end
    (@metrics.one? || @metrics.keys == [:estimated_revenue, :estimated_minutes_watched]) ? hash[@metrics.keys.first] : hash
  end
# NOTE: Once in a while, YouTube responds with 400 Error and the message
# "Invalid query. Query did not conform to the expectations."; in this
# case running the same query after one second fixes the issue. This is
# not documented by YouTube and hardly testable, but trying again the
# same query is a workaround that works and can hardly cause any damage.
# Similarly, once in while YouTube responds with a random 503 error.
rescue Yt::Error => e
  (max_retries > 0) && rescue?(e) ? sleep(retry_time) && within(days_range, country, state, dimension, videos, historical, max_retries - 1) : raise
end

Private Instance Methods

items_key() click to toggle source
# File lib/yt/collections/reports.rb, line 214
def items_key
  'rows'
end
list_params() click to toggle source

@see developers.google.com/youtube/analytics/v1/content_owner_reports

Calls superclass method Yt::Actions::List#list_params
# File lib/yt/collections/reports.rb, line 177
def list_params
  super.tap do |params|
    params[:host] = 'youtubeanalytics.googleapis.com'
    params[:path] = '/v2/reports'
    params[:params] = reports_params
    params[:camelize_params] = false
  end
end
new_item(data) click to toggle source
# File lib/yt/collections/reports.rb, line 172
def new_item(data)
  instance_exec *data, &DIMENSIONS[@dimension][:parse]
end
reports_params() click to toggle source
# File lib/yt/collections/reports.rb, line 186
def reports_params
  @parent.reports_params.tap do |params|
    params['startDate'] = @days_range.begin
    params['endDate'] = @days_range.end
    params['metrics'] = @metrics.keys.join(',').to_s.camelize(:lower)
    params['dimensions'] = DIMENSIONS[@dimension][:name] unless @dimension == :range
    params['includeHistoricalChannelData'] = @historical if @historical
    params['maxResults'] = 50 if @dimension.in? [:playlist, :video]
    params['maxResults'] = 25 if @dimension.in? [:embedded_player_location, :related_video, :search_term, :referrer]
    if @dimension.in? [:video, :playlist, :embedded_player_location, :related_video, :search_term, :referrer]
      if @metrics.keys == [:estimated_revenue, :estimated_minutes_watched]
        params['sort'] = '-estimatedRevenue'
      else
        params['sort'] = "-#{@metrics.keys.join(',').to_s.camelize(:lower)}"
      end
    end
    params[:filters] = "video==#{@videos.join ','}" if @videos
    params[:filters] = ((params[:filters] || '').split(';') + ["country==US"]).compact.uniq.join(';') if @dimension == :state && !@state
    params[:filters] = ((params[:filters] || '').split(';') + ["country==#{@country}"]).compact.uniq.join(';') if @country && !@state
    params[:filters] = ((params[:filters] || '').split(';') + ["province==US-#{@state}"]).compact.uniq.join(';') if @state
    params[:filters] = ((params[:filters] || '').split(';') + ['isCurated==1']).compact.uniq.join(';') if @dimension == :playlist
    params[:filters] = ((params[:filters] || '').split(';') + ['insightPlaybackLocationType==EMBEDDED']).compact.uniq.join(';') if @dimension == :embedded_player_location
    params[:filters] = ((params[:filters] || '').split(';') + ['insightTrafficSourceType==RELATED_VIDEO']).compact.uniq.join(';') if @dimension == :related_video
    params[:filters] = ((params[:filters] || '').split(';') + ['insightTrafficSourceType==YT_SEARCH']).compact.uniq.join(';') if @dimension == :search_term
    params[:filters] = ((params[:filters] || '').split(';') + ['insightTrafficSourceType==EXT_URL']).compact.uniq.join(';') if @dimension == :referrer
  end
end
rescue?(error) click to toggle source
# File lib/yt/collections/reports.rb, line 218
def rescue?(error)
  'badRequest'.in?(error.reasons) && error.to_s =~ /did not conform/
end
retry_time() click to toggle source
# File lib/yt/collections/reports.rb, line 161
def retry_time
  3
end
type_cast(value, type) click to toggle source
# File lib/yt/collections/reports.rb, line 165
def type_cast(value, type)
  case [type]
    when [Integer] then value.to_i if value
    when [Float] then value.to_f if value
  end
end