app/models/asset/statistics.rb
# frozen_string_literal: true
class Asset < ApplicationRecord
module Statistics
extend ActiveSupport::Concern
LAUNCH_DATE = 'Tue Jan 01 00:00:00 +0100 2008'.to_time.freeze
def calculate_hotness
(guest_play_count + (alonetoner_play_count * 2) + (unique_alonetoner_count * 4) - uncool_self_plays).to_f * age_ratio.to_f
end
# https://www.desmos.com/calculator/gwnliinim2
# after about 20 listens, it "compresses" the value of guest listens
def guest_play_count(from = 30.days.ago)
num = listens.where("listens.created_at > (?) AND listens.listener_id is null", from).count
-7 + (0.19 * num.to_f) + Math.log((num.to_f + 5), 1.25)
end
def listens_per_week
listens.count(:all,
conditions: ['listens.listener_id != ?', user_id]).to_f * 7 / days_old
rescue StandardError
0
end
def uncool_self_plays(_from = 30.days.ago)
emphasis = 2.0
allowance = 3.0
uncool_plays = total_uncool_self_plays - allowance
uncool_plays = (uncool_plays + uncool_plays.abs) / 2 # never want it to be below zero
uncool_plays * emphasis
end
def total_uncool_self_plays(from = 30.days.ago)
user_plays = listens.where(listener_id: user.similar_users_by_ip).where("listens.created_at > (?)", from).count
end
def alonetoner_play_count(from = 30.days.ago)
listens.where("listener_id is not null").where("listens.created_at > (?)", from).count.to_f - total_uncool_self_plays.to_f
end
def unique_alonetoner_count(from = 30.days.ago)
alonetoners = listens.select('distinct listener_id').where("listens.created_at > (?)", from).count
this_user = listens.select('distinct listener_id').where("listens.created_at > (?)", from).where(listener_id: user.similar_users_by_ip).count
total = alonetoners - this_user - 1
(total + total.abs) / 2 # ensure postitive number or zero
end
def bandwidth_used
(listens.count * mp3_file_size).to_f / 1024 / 1024 / 1024
end
def days_old
((Time.now - created_at) / 60 / 60 / 24).ceil
end
def age_ratio
case days_old
when 0..1 then 100.0
when 1..2 then 80.0
when 2..3 then 70.0
when 3..4 then 50.0
when 5..7 then 35.0
when 8..13 then 10.0
when 14..30 then 2.0
when 31..90 then 0.1
else 0.01
end
end
def plays_by_month
listens.count(:all, group: 'MONTH(listens.created_at)', include: nil, conditions: ['listens.created_at > ?', 1.year.ago])
end
module ClassMethods
def days
(Asset.sum(:length).to_f / 60 / 60 / 24).to_i.to_s
end
def gigs
(Asset.sum(:mp3_file_size).to_f / 1024 / 1024 / 1024).to_s[0..3]
end
def update_hotness
Asset.find_each do |a|
# These use update_all so that they do not trigger callbacks and invalidate cache
a.update_columns(hotness: a.calculate_hotness, listens_per_week: a.listens_per_week)
end
end
# iterate through the months
def sum_up_the_months(date = Time.now)
sum = 0
while date < Time.now
result, label = monthly_sum_for(date)
sum += result
yield label, sum
date += 1.month
end
end
def monthly_chart
monthly_counts = []
sum_up_the_months(LAUNCH_DATE) { |date, sum| monthly_counts << [sum, date] }
monthly_counts
end
def monthly_sum_for(date = Time.now, sum = 0)
# [count, year_month_label]
month_count = count(:all,
conditions: [
'created_at > ? AND created_at < ?',
date.beginning_of_month,
date.end_of_month
])
[sum + month_count, date.strftime('%b %y').to_s]
end
end
end
end