module JamRuby class Mix < ActiveRecord::Base include S3ManagerMixin MAX_MIX_TIME = 7200 # 2 hours before_destroy :delete_s3_files self.primary_key = 'id' belongs_to :recording, :class_name => "JamRuby::Recording", :inverse_of => :mixes def self.schedule(recording) raise if recording.nil? mix = Mix.new mix.recording = recording mix.save mix.url = construct_filename(mix.created_at, recording.id, mix.id) if mix.save mix.enqueue end mix end def enqueue begin Resque.enqueue(AudioMixer, self.id, self.sign_put) rescue # implies redis is down. we don't update started_at false end Mix.where(:id => self.id).update_all(:started_at => Time.now) true end def can_download?(some_user) !ClaimedRecording.find_by_user_id_and_recording_id(some_user.id, recording_id).nil? end def errored(reason, detail) self.error_reason = reason self.error_detail = detail self.error_count = self.error_count + 1 save end def finish(length, md5) self.completed_at = Time.now self.length = length self.md5 = md5 self.completed = true if save recording.users.each do |user| Notification.send_download_available(user.id) end end end # valid for 1 day; because the s3 urls eventually expire def manifest one_day = 60 * 60 * 24 manifest = { "files" => [], "timeline" => [] } mix_params = [] recording.recorded_tracks.each do |recorded_track| manifest["files"] << { "filename" => recorded_track.sign_url(one_day), "codec" => "vorbis", "offset" => 0 } mix_params << { "level" => 100, "balance" => 0 } end manifest["timeline"] << { "timestamp" => 0, "mix" => mix_params } manifest["output"] = { "codec" => "vorbis" } manifest["recording_id"] = self.id manifest end def s3_url s3_manager.s3_url(url) end def is_completed completed end def sign_url(expiration_time = 120) # expire link in 1 minute--the expectation is that a client is immediately following this link s3_manager.sign_url(self.url, {:expires => expiration_time, :response_content_type => 'audio/ogg', :secure => false}) end def sign_put(expiration_time = 3600 * 24) s3_manager.sign_url(self.url, {:expires => expiration_time, :content_type => 'audio/ogg', :secure => false}, :put) end def self.queue_jobs_needing_retry Mix.find_each(:conditions => 'should_retry = TRUE or started_at is NULL', :batch_size => 100) do |mix| mix.enqueue end end private def delete_s3_files s3_manager.delete(filename) end def filename # construct a path for s3 Mix.construct_filename(self.created_at, self.recording.id, self.id) end def self.construct_filename(created_at, recording_id, id) raise "unknown ID" unless id "recordings/#{created_at.strftime('%m-%d-%Y')}/#{recording_id}/mix-#{id}.ogg" end end end