# An item to be sent to dubbletrack. Either a track or a traffic update, can be created from a hash or a db record # module DubbletrackRemote module DubbletrackRemote class Item < ActiveRecord::Base TRACK = "track" TRAFFIC = "traffic" # TODO: fix these scopes so they're not so horrendous, is there a way to make sqlite play nicer with booleans? scope :successful, -> { where(["success = ? OR success = ?", 1, true]) } scope :known, -> { where("item_type IN (?)", [TRACK, TRAFFIC]) } scope :remaining, -> { known.where(["(success IS NULL OR success = ?) AND (last_error_text IS NULL OR last_error_text != ?)", false, "Played at has already been taken"]) } scope :tracks, -> { where(["item_type = ?", TRACK]) } scope :traffic, -> { where(["item_type = ?", TRAFFIC]) } scope :recent_remaining, -> { remaining.where(["played_at > ?", 1.day.ago]) } scope :next, ->(count = 10) { remaining.order("played_at desc").limit(count) } scope :on_date, ->(time) { where(["played_at >= ? AND played_at <= ?", time.beginning_of_day, time.end_of_day]) } validates :played_at, uniqueness: true # validates :intended_played_at, uniqueness: true, allow_blank: true before_validation :set_item_type before_save :set_item_type attr_accessor :raw def played_at_with_delay played_at + (Settings&.automation&.delay_seconds || 0).seconds rescue played_at end def set_item_type self.item_type = detect_item_type end def detect_item_type return TRACK if track? return TRAFFIC if traffic? end def key "#{played_at.utc.iso8601}-#{title}:#{artist_name}" end def track? title.present? && played_at.present? && artist_name.present? && (label_name.present? || release_name.present?) # label name and release name could technically be left out, even though they shouldn't end def traffic? title.present? && played_at.present? && !track? end def pretty_print state = if success "[✓] " elsif last_error_code "[×] " else "[ ] " end duration_s = duration ? " [#{duration}s]" : "" if track? line = "TRACK: #{state}#{id}:#{played_at.utc.iso8601}".ljust(30) + "#{title} - #{artist_name}" "\r\n" + " ".ljust(32) + "#{release_name} // #{label_name} \r\n" + " ".ljust(32) + "#{genre}, #{duration_s}, #{automation_group}, #{automation_id}" + "\r\n" + (last_error_code ? "".ljust(30) + "[#{last_error_code}] #{last_error_text}" : "") + "\r\n" elsif traffic? line = "TRAFFIC: #{state}#{id}:#{played_at.utc.iso8601}".ljust(30) + title.to_s + "\r\n" + "#{genre}, #{duration_s}, #{automation_group}, #{automation_id}" + "\r\n" + (last_error_code ? "".ljust(30) + "[#{last_error_code}] #{last_error_text}" : "") + "\r\n" else line = "UNKNOWN: #{state}#{id}:#{played_at.utc.iso8601}".ljust(30) + title.to_s + "\r\n" + "#{genre}, #{duration_s}, #{automation_group}, #{automation_id}" + "\r\n" + (last_error_code ? "".ljust(30) + "[#{last_error_code}] #{last_error_text}" : "") + "\r\n" end end end end