From 1cd57cb4e854b52ed1ffd90706d690f0480f2f61 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Fri, 1 May 2015 12:09:18 -0500 Subject: [PATCH] * VRFS-3118 - check for high latency while in session, VRFS-3138 - fix tons of issues with user downloading both sample rates --- db/manifest | 1 + db/up/jam_track_right_private_key.sql | 11 + .../app/uploaders/jam_track_right_uploader.rb | 2 +- ruby/lib/jam_ruby/jam_tracks_manager.rb | 16 +- ruby/lib/jam_ruby/models/jam_track_right.rb | 40 +- .../lib/jam_ruby/resque/jam_tracks_builder.rb | 9 +- .../jam_ruby/models/jam_track_right_spec.rb | 21 +- .../resque/jam_tracks_builder_spec.rb | 14 +- .../resque/jam_tracks_cleaner_spec.rb | 4 +- web/app/assets/javascripts/backend_alerts.js | 5 +- .../javascripts/dialog/openJamTrackDialog.js | 14 +- .../dialog/recordingFinishedDialog.js | 7 +- .../javascripts/download_jamtrack.js.coffee | 15 +- .../assets/javascripts/playbackControls.js | 9 +- .../javascripts/scheduled_session.js.erb | 6 +- web/app/assets/javascripts/session.js | 349 +++++++++--------- web/app/assets/javascripts/session_utils.js | 27 +- web/app/assets/javascripts/shopping_cart.js | 2 +- web/app/assets/javascripts/utils.js | 65 +--- .../assets/javascripts/wizard/gear_utils.js | 115 +++++- .../stylesheets/playbackControls.css.scss | 1 + .../controllers/api_jam_tracks_controller.rb | 30 +- web/app/views/api_jam_tracks/keys.rabl | 24 +- web/config/application.rb | 1 - web/config/initializers/gon.rb | 1 - .../api_jam_tracks_controller_spec.rb | 72 ++-- web/spec/features/jamtrack_shopping_spec.rb | 10 +- 27 files changed, 523 insertions(+), 348 deletions(-) create mode 100644 db/up/jam_track_right_private_key.sql diff --git a/db/manifest b/db/manifest index c79ea8187..4740e840a 100755 --- a/db/manifest +++ b/db/manifest @@ -280,3 +280,4 @@ signup_hints.sql packaging_notices.sql first_played_jamtrack_at.sql payment_history.sql +jam_track_right_private_key.sql diff --git a/db/up/jam_track_right_private_key.sql b/db/up/jam_track_right_private_key.sql new file mode 100644 index 000000000..a0e9b9d01 --- /dev/null +++ b/db/up/jam_track_right_private_key.sql @@ -0,0 +1,11 @@ +ALTER TABLE jam_track_rights ADD COLUMN private_key_44 VARCHAR; +ALTER TABLE jam_track_rights ADD COLUMN private_key_48 VARCHAR; +ALTER TABLE jam_track_rights ADD COLUMN signed_48 BOOLEAN NOT NULL DEFAULT FALSE; +ALTER TABLE jam_track_rights ADD COLUMN signed_44 BOOLEAN NOT NULL DEFAULT FALSE; +ALTER TABLE jam_track_rights DROP COLUMN private_key; +ALTER TABLE jam_track_rights DROP COLUMN signed; +ALTER TABLE jam_track_rights ADD COLUMN signing_started_at_44 TIMESTAMP; +ALTER TABLE jam_track_rights ADD COLUMN signing_started_at_48 TIMESTAMP; +ALTER TABLE jam_track_rights DROP COLUMN signing_started_at; + + diff --git a/ruby/lib/jam_ruby/app/uploaders/jam_track_right_uploader.rb b/ruby/lib/jam_ruby/app/uploaders/jam_track_right_uploader.rb index e33494063..520908b7b 100644 --- a/ruby/lib/jam_ruby/app/uploaders/jam_track_right_uploader.rb +++ b/ruby/lib/jam_ruby/app/uploaders/jam_track_right_uploader.rb @@ -23,6 +23,6 @@ class JamTrackRightUploader < CarrierWave::Uploader::Base end def filename - "#{model.store_dir}/#{model.filename}" if model.id + "#{model.store_dir}/#{model.filename(mounted_as)}" if model.id end end diff --git a/ruby/lib/jam_ruby/jam_tracks_manager.rb b/ruby/lib/jam_ruby/jam_tracks_manager.rb index 36a19c960..644f9ccc3 100644 --- a/ruby/lib/jam_ruby/jam_tracks_manager.rb +++ b/ruby/lib/jam_ruby/jam_tracks_manager.rb @@ -82,10 +82,18 @@ module JamRuby else jam_track_right.url_44.store!(File.open(output_jkz, "rb")) end - - jam_track_right.signed=true - jam_track_right.downloaded_since_sign=false - jam_track_right.private_key=File.read("#{tmp_dir}/skey.pem") + + if sample_rate == 48 + jam_track_right.signed_48 = true + jam_track_right.private_key_48 = File.read("#{tmp_dir}/skey.pem") + else + jam_track_right.signed_44 = true + jam_track_right.private_key_44 = File.read("#{tmp_dir}/skey.pem") + end + + jam_track_right.signing_queued_at = nil # if left set, throws off signing_state on subsequent signing attempts + jam_track_right.downloaded_since_sign = false + jam_track_right.save! end end # mktmpdir diff --git a/ruby/lib/jam_ruby/models/jam_track_right.rb b/ruby/lib/jam_ruby/models/jam_track_right.rb index a5e127d78..b60bf9755 100644 --- a/ruby/lib/jam_ruby/models/jam_track_right.rb +++ b/ruby/lib/jam_ruby/models/jam_track_right.rb @@ -29,7 +29,7 @@ module JamRuby # try to catch major transitions: # if just queue time changes, start time changes, or signed time changes, send out a notice - if signing_queued_at_was != signing_queued_at || signing_started_at_was != signing_started_at || last_signed_at_was != last_signed_at || current_packaging_step != current_packaging_step_was || packaging_steps != packaging_steps_was + if signing_queued_at_was != signing_queued_at || signing_started_at_48_was != signing_started_at_48 || signing_started_at_44_was != signing_started_at_44 || last_signed_at_was != last_signed_at || current_packaging_step != current_packaging_step_was || packaging_steps != packaging_steps_was SubscriptionMessage.jam_track_signing_job_change(self) end end @@ -39,8 +39,8 @@ module JamRuby end # create name of the file - def filename - "#{jam_track.name}.jkz" + def filename(bitrate) + "#{jam_track.name}-#{bitrate == :url_48 ? '48' : '44'}.jkz" end def verify_download_count @@ -71,11 +71,12 @@ module JamRuby if bitrate==48 self.length_48 = length self.md5_48 = md5 + self.signed_48 = true else self.length_44 = length self.md5_44 = md5 + self.signed_44 = true end - self.signed = true self.error_count = 0 self.error_reason = nil self.error_detail = nil @@ -104,7 +105,7 @@ module JamRuby def enqueue(sample_rate=48) begin - JamTrackRight.where(:id => self.id).update_all(:signing_queued_at => Time.now, :signing_started_at => nil, :last_signed_at => nil) + JamTrackRight.where(:id => self.id).update_all(:signing_queued_at => Time.now, :signing_started_at_44 => nil, :signing_started_at_48 => nil, :last_signed_at => nil) Resque.enqueue(JamTracksBuilder, self.id, sample_rate) true rescue Exception => e @@ -116,7 +117,7 @@ module JamRuby # if the job is already signed, just queued up for signing, or currently signing, then don't enqueue... otherwise fire it off def enqueue_if_needed(sample_rate=48) - state = signing_state + state = signing_state(sample_rate) if state == 'SIGNED' || state == 'SIGNING' || state == 'QUEUED' false else @@ -129,9 +130,9 @@ module JamRuby # @return true if signed && file exists for the sample_rate specifed: def ready?(sample_rate=48) if sample_rate==48 - self.signed && self.url_48.present? && self.url_48.file.exists? + self.signed_48 && self.url_48.present? && self.url_48.file.exists? else - self.signed && self.url_44.present? && self.url_44.file.exists? + self.signed_44 && self.url_44.present? && self.url_44.file.exists? end end @@ -143,8 +144,20 @@ module JamRuby # QUEUED_TIMEOUT - the package signing job (JamTrackBuilder) was queued, but never executed # QUEUED - the package is queued to sign # QUIET - the jam_track_right exists, but no job has been kicked off; a job needs to be enqueued - def signing_state + def signing_state(sample_rate = nil) state = nil + + # if the caller did not specified sample rate, we will determine what signing state to check by looking at the most recent signing attempt + if sample_rate.nil? + # determine what package is being signed by checking the most recent signing_started at + time_48 = signing_started_at_48.to_i + time_44 = signing_started_at_44.to_i + sample_rate = time_48 > time_44 ? 48 : 44 + end + + signed = sample_rate == 48 ? signed_48 : signed_44 + signing_started_at = sample_rate == 48 ? signing_started_at_48 : signing_started_at_44 + if signed state = 'SIGNED' elsif signing_started_at @@ -170,11 +183,16 @@ module JamRuby end state end + + def signed?(sample_rate) + sample_rate == 48 ? signed_48 : signed_44 + end + def update_download_count(count=1) self.download_count = self.download_count + count self.last_downloaded_at = Time.now - if self.signed + if self.signed_44 || self.signed_48 self.downloaded_since_sign = true end end @@ -184,7 +202,7 @@ module JamRuby return [] end - JamTrack.select('jam_tracks.id, jam_track_rights.private_key AS private_key, jam_track_rights.id AS jam_track_right_id') + JamTrack.select('jam_tracks.id, jam_track_rights.private_key_44 AS private_key_44, jam_track_rights.private_key_48 AS private_key_48, jam_track_rights.id AS jam_track_right_id') .joins("LEFT OUTER JOIN jam_track_rights ON jam_tracks.id = jam_track_rights.jam_track_id AND jam_track_rights.user_id = '#{user.id}'") .where('jam_tracks.id IN (?)', jamtracks) end diff --git a/ruby/lib/jam_ruby/resque/jam_tracks_builder.rb b/ruby/lib/jam_ruby/resque/jam_tracks_builder.rb index 329a52b4d..71018e1bd 100644 --- a/ruby/lib/jam_ruby/resque/jam_tracks_builder.rb +++ b/ruby/lib/jam_ruby/resque/jam_tracks_builder.rb @@ -29,7 +29,7 @@ module JamRuby @jam_track_right = JamTrackRight.find(jam_track_right_id) # bailout check - if @jam_track_right.signed + if @jam_track_right.signed?(bitrate) log.debug("package is already signed. bailing") return end @@ -39,12 +39,13 @@ module JamRuby # track that it's started ( and avoid db validations ) signing_started_at = Time.now + signing_started_model_symbol = bitrate == 48 ? :signing_started_at_48 : :signing_started_at_44 last_step_at = Time.now - JamTrackRight.where(:id => @jam_track_right.id).update_all(:signing_started_at => signing_started_at, :should_retry => false, packaging_steps: total_steps, current_packaging_step: 0, last_step_at: last_step_at) - # because we are skiping after_save, we have to keep the model current for the notification. A bit ugly... + JamTrackRight.where(:id => @jam_track_right.id).update_all(signing_started_model_symbol => signing_started_at, :should_retry => false, packaging_steps: total_steps, current_packaging_step: 0, last_step_at: last_step_at) + # because we are skipping 'after_save', we have to keep the model current for the notification. A bit ugly... @jam_track_right.current_packaging_step = 0 @jam_track_right.packaging_steps = total_steps - @jam_track_right.signing_started_at = signing_started_at + @jam_track_right[signing_started_model_symbol] = signing_started_at @jam_track_right.should_retry = false @jam_track_right.last_step_at = Time.now SubscriptionMessage.jam_track_signing_job_change(@jam_track_right) diff --git a/ruby/spec/jam_ruby/models/jam_track_right_spec.rb b/ruby/spec/jam_ruby/models/jam_track_right_spec.rb index 0977703ff..90953fc3b 100644 --- a/ruby/spec/jam_ruby/models/jam_track_right_spec.rb +++ b/ruby/spec/jam_ruby/models/jam_track_right_spec.rb @@ -76,7 +76,7 @@ describe JamTrackRight do JamRuby::JamTracksManager.save_jam_track_jkz(user, jam_track) #}.to_not raise_error(ArgumentError) jam_track_right.reload - jam_track_right[:url_48].should == jam_track_right.store_dir + '/' + jam_track_right.filename + jam_track_right[:url_48].should == jam_track_right.store_dir + '/' + jam_track_right.filename(:url_48) # verify it's on S3 url = jam_track_right[:url_48] @@ -109,11 +109,12 @@ describe JamTrackRight do end it "valid track with rights to it by querying user" do - jam_track_right = FactoryGirl.create(:jam_track_right, private_key: 'keyabc') + jam_track_right = FactoryGirl.create(:jam_track_right, private_key_44: 'keyabc') keys = JamTrackRight.list_keys(jam_track_right.user, [jam_track_right.jam_track.id]) keys.should have(1).items keys[0].id.should == jam_track_right.jam_track.id - keys[0]['private_key'].should eq('keyabc') + keys[0]['private_key_44'].should eq('keyabc') + keys[0]['private_key_48'].should be_nil end end @@ -124,7 +125,7 @@ describe JamTrackRight do end it "signed" do - right = FactoryGirl.create(:jam_track_right, signed: true) + right = FactoryGirl.create(:jam_track_right, signed_44: true, signing_started_at_44: Time.now) right.signing_state.should eq('SIGNED') end @@ -134,23 +135,23 @@ describe JamTrackRight do end it "signing" do - right = FactoryGirl.create(:jam_track_right, signing_started_at: Time.now, packaging_steps: 3, current_packaging_step:0, last_step_at:Time.now) - right.signing_state.should eq('SIGNING') + right = FactoryGirl.create(:jam_track_right, signing_started_at_44: Time.now, packaging_steps: 3, current_packaging_step:0, last_step_at:Time.now) + right.signing_state(44).should eq('SIGNING') end it "signing timeout" do - right = FactoryGirl.create(:jam_track_right, signing_started_at: Time.now - 100, packaging_steps: 3, current_packaging_step:0, last_step_at:Time.now) - right.signing_state.should eq('SIGNING_TIMEOUT') + right = FactoryGirl.create(:jam_track_right, signing_started_at_48: Time.now - 100, packaging_steps: 3, current_packaging_step:0, last_step_at:Time.now) + right.signing_state(48).should eq('SIGNING_TIMEOUT') end it "queued" do right = FactoryGirl.create(:jam_track_right, signing_queued_at: Time.now) - right.signing_state.should eq('QUEUED') + right.signing_state(44).should eq('QUEUED') end it "signing timeout" do right = FactoryGirl.create(:jam_track_right, signing_queued_at: Time.now - (APP_CONFIG.signing_job_queue_max_time + 1)) - right.signing_state.should eq('QUEUED_TIMEOUT') + right.signing_state(44).should eq('QUEUED_TIMEOUT') end end diff --git a/ruby/spec/jam_ruby/resque/jam_tracks_builder_spec.rb b/ruby/spec/jam_ruby/resque/jam_tracks_builder_spec.rb index 7ead35e3a..982c56f87 100644 --- a/ruby/spec/jam_ruby/resque/jam_tracks_builder_spec.rb +++ b/ruby/spec/jam_ruby/resque/jam_tracks_builder_spec.rb @@ -44,8 +44,13 @@ describe JamTracksBuilder do jam_track_right[:url_44].should be_nil JamTracksBuilder.perform(jam_track_right.id, 48) jam_track_right.reload - jam_track_right[:url_48].should == jam_track_right.store_dir + '/' + jam_track_right.filename + jam_track_right[:url_48].should == jam_track_right.store_dir + '/' + jam_track_right.filename(:url_48) jam_track_track[:url_44].should be_nil + + jam_track_right.signed_48.should be_true + jam_track_right.signing_started_at_48.should_not be_nil + jam_track_right.signed_44.should be_false + jam_track_right.signing_started_at_44.should be_nil end describe "with bitrate 44" do @@ -76,9 +81,14 @@ describe JamTracksBuilder do jam_track_right[:url_48].should be_nil JamTracksBuilder.perform(jam_track_right.id, 44) jam_track_right.reload - jam_track_right[:url_44].should == jam_track_right.store_dir + '/' + jam_track_right.filename + jam_track_right[:url_44].should == jam_track_right.store_dir + '/' + jam_track_right.filename(:url_44) jam_track_right.url_44.should_not be_nil jam_track_track[:url_48].should be_nil + + jam_track_right.signed_44.should be_true + jam_track_right.signing_started_at_44.should_not be_nil + jam_track_right.signed_48.should be_false + jam_track_right.signing_started_at_48.should be_nil end end end \ No newline at end of file diff --git a/ruby/spec/jam_ruby/resque/jam_tracks_cleaner_spec.rb b/ruby/spec/jam_ruby/resque/jam_tracks_cleaner_spec.rb index 1c900bc52..e8a244b14 100644 --- a/ruby/spec/jam_ruby/resque/jam_tracks_cleaner_spec.rb +++ b/ruby/spec/jam_ruby/resque/jam_tracks_cleaner_spec.rb @@ -23,14 +23,14 @@ describe JamTracksCleaner do it "should clean" do jam_track_right = JamTrackRight.create(:user=>@user, :jam_track=>@jam_track) - jam_track_right.signed=true + jam_track_right.signed_48=true jam_track_right jam_track_right.url_48.store!(File.open(RIGHT_NAME)) jam_track_right.downloaded_since_sign=true jam_track_right.save! - jam_track_right[:url_48].should == jam_track_right.store_dir + '/' + jam_track_right.filename + jam_track_right[:url_48].should == jam_track_right.store_dir + '/' + jam_track_right.filename(:url_48) jam_track_right.reload # Should exist after uploading: diff --git a/web/app/assets/javascripts/backend_alerts.js b/web/app/assets/javascripts/backend_alerts.js index d1c9628e1..b2ef4b7cf 100644 --- a/web/app/assets/javascripts/backend_alerts.js +++ b/web/app/assets/javascripts/backend_alerts.js @@ -69,7 +69,10 @@ logger.debug("alert callback", type, text); - var alertData = ALERT_TYPES[type]; + var alertData = $.extend({}, ALERT_TYPES[type]); + + alertData.text = text; + if(alertData) { $document.triggerHandler(alertData.name, alertData); } diff --git a/web/app/assets/javascripts/dialog/openJamTrackDialog.js b/web/app/assets/javascripts/dialog/openJamTrackDialog.js index 9f0fc5ce6..8843838f5 100644 --- a/web/app/assets/javascripts/dialog/openJamTrackDialog.js +++ b/web/app/assets/javascripts/dialog/openJamTrackDialog.js @@ -13,6 +13,8 @@ var $templateOpenJamTrackRow = null; var $downloadedTrackHelp = null; var $whatAreJamTracks = null; + var sampleRate = null; + var sampleRateForFilename = null; function emptyList() { @@ -24,18 +26,25 @@ } function beforeShow() { + + } + + function afterShow() { $dialog.data('result', null) emptyList(); resetPagination(); showing = true; + sampleRate = context.jamClient.GetSampleRate() + sampleRateForFilename = sampleRate == 48 ? '48' : '44'; + getPurchasedJamTracks(0) .done(function(data, textStatus, jqXHR) { // initialize pagination var $paginator = context.JK.Paginator.create(parseInt(jqXHR.getResponseHeader('total-entries')), perPage, 0, onPageSelected) $paginatorHolder.append($paginator); }); - } + } function afterHide() { showing = false; } @@ -58,7 +67,7 @@ options.jamTrackId = jamTrack.id; options.name = jamTrack.name; options.artist = jamTrack.original_artist; - var detail = context.jamClient.JamTrackGetTrackDetail(jamTrack.id) || {} + var detail = context.jamClient.JamTrackGetTrackDetail(jamTrack.id + '-' + sampleRateForFilename) || {} options.downloaded = detail.key_state == 'ready' ? 'Yes' : 'No' var $tr = $(context._.template($templateOpenJamTrackRow.html(), options, { variable: 'data' })); @@ -99,6 +108,7 @@ function initialize(){ var dialogBindings = { 'beforeShow' : beforeShow, + 'afterShow' : afterShow, 'afterHide': afterHide }; diff --git a/web/app/assets/javascripts/dialog/recordingFinishedDialog.js b/web/app/assets/javascripts/dialog/recordingFinishedDialog.js index 866e460a1..6152927a2 100644 --- a/web/app/assets/javascripts/dialog/recordingFinishedDialog.js +++ b/web/app/assets/javascripts/dialog/recordingFinishedDialog.js @@ -108,6 +108,10 @@ context.jamClient.ClosePreviewRecording(); } + function onCancel() { + return false; + } + function discardRecording(e) { resetForm(); @@ -323,7 +327,8 @@ function initialize() { var dialogBindings = { 'beforeShow': beforeShow, - 'afterHide': afterHide + 'afterHide': afterHide, + 'onCancel': onCancel }; app.bindDialog('recordingFinished', dialogBindings); diff --git a/web/app/assets/javascripts/download_jamtrack.js.coffee b/web/app/assets/javascripts/download_jamtrack.js.coffee index 0854d49db..800cdc276 100644 --- a/web/app/assets/javascripts/download_jamtrack.js.coffee +++ b/web/app/assets/javascripts/download_jamtrack.js.coffee @@ -205,6 +205,8 @@ context.JK.DownloadJamTrack = class DownloadJamTrack showInitial: () => @logger.debug("showing #{@state.name}") + @sampleRate = context.jamClient.GetSampleRate() + @sampleRateForFilename = if @sampleRate == 48 then '48' else '44' @attempts = @attempts + 1 this.expectTransition() context.JK.SubscriptionUtils.subscribe('jam_track_right', @jamTrack.jam_track_right_id).on(context.JK.EVENTS.SUBSCRIBE_NOTIFICATION, this.onJamTrackRightEvent) @@ -350,17 +352,18 @@ context.JK.DownloadJamTrack = class DownloadJamTrack checkState: () => # check for the success state against the local state of the client... if it's playable, then we should be OK - @trackDetail = context.jamClient.JamTrackGetTrackDetail (@jamTrack.id) + fqId = "#{@jamTrack.id}-#{@sampleRateForFilename}" + @trackDetail = context.jamClient.JamTrackGetTrackDetail (fqId) - @logger.debug("DownloadJamTrack: JamTrackGetTrackDetail.key_state: " + @trackDetail.key_state) + @logger.debug("DownloadJamTrack: JamTrackGetTrackDetail(#{fqId}).key_state: " + @trackDetail.key_state, @trackDetail) # first check if the version is not the same; if so, invalidate. if @trackDetail.version? if @jamTrack.version != @trackDetail.version @logger.info("DownloadJamTrack: JamTrack on disk is different version (stored: #{@trackDetail.version}, server: #{@jamTrack.version}. Invalidating") - context.jamClient.InvalidateJamTrack(@jamTrack.id) - @trackDetail = context.jamClient.JamTrackGetTrackDetail (@jamTrack.id) + context.jamClient.InvalidateJamTrack("#{@jamTrack.id}-#{@sampleRateForFilename}") + @trackDetail = context.jamClient.JamTrackGetTrackDetail ("#{@jamTrack.id}-#{@sampleRateForFilename}") if @trackDetail.version? @logger.error("after invalidating package, the version is still wrong!") @@ -447,9 +450,7 @@ context.JK.DownloadJamTrack = class DownloadJamTrack @attemptedEnqueue = true @ajaxEnqueueAborted = false - sampleRate = context.jamClient.GetSampleRate() - - @rest.enqueueJamTrack({id: @jamTrack.id, sample_rate: sampleRate}) + @rest.enqueueJamTrack({id: @jamTrack.id, sample_rate: @sampleRate}) .done(this.processEnqueueJamTrack) .fail(this.processEnqueueJamTrackFail) diff --git a/web/app/assets/javascripts/playbackControls.js b/web/app/assets/javascripts/playbackControls.js index 2aeaf0632..1634150c1 100644 --- a/web/app/assets/javascripts/playbackControls.js +++ b/web/app/assets/javascripts/playbackControls.js @@ -53,6 +53,7 @@ var playbackMode = PlaybackMode.EveryWhere; var monitorPlaybackTimeout = null; var playbackMonitorMode = PLAYBACK_MONITOR_MODE.MEDIA_FILE; + var monitoring = false; function init() { updateSliderPosition(0); @@ -210,6 +211,9 @@ } } function monitorRecordingPlayback() { + if(!monitoring) { + return; + } if(playbackMonitorMode == PLAYBACK_MONITOR_MODE.JAMTRACK) { var positionMs = context.jamClient.SessionCurrrentJamTrackPlayPosMs(); var duration = context.jamClient.SessionGetJamTracksPlayDurationMs(); @@ -262,7 +266,7 @@ } // at the end of the play, the duration sets to 0, as does currentTime. but isPlaying does not reset to - //logger.debug("currentTimeMs, durationTimeMs, mode", currentTimeMs, durationTimeMs, playbackMonitorMode); + logger.debug("currentTimeMs, durationTimeMs, mode", currentTimeMs, durationTimeMs, playbackMonitorMode); if(currentTimeMs == 0 && seenActivity) { if(playbackPlaying) { isPlaying = false; @@ -355,7 +359,7 @@ } function startMonitor(_playbackMonitorMode) { - + monitoring = true; // resets everything to zero init(); @@ -373,6 +377,7 @@ } function stopMonitor() { + monitoring = false; logger.debug("playbackControl.stopMonitor") if(monitorPlaybackTimeout!= null) { clearTimeout(monitorPlaybackTimeout); diff --git a/web/app/assets/javascripts/scheduled_session.js.erb b/web/app/assets/javascripts/scheduled_session.js.erb index 707d63554..cfaf2bd4e 100644 --- a/web/app/assets/javascripts/scheduled_session.js.erb +++ b/web/app/assets/javascripts/scheduled_session.js.erb @@ -932,9 +932,9 @@ } if(optionRequiresMultiplayerProfile()) { - if(context.JK.guardAgainstSinglePlayerProfile(app).canPlay == false) { - return false; - } + // if(context.JK.guardAgainstSinglePlayerProfile(app).canPlay == false) { + // return false; + //} } var valid = beforeMoveStep(); diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js index 58cfb6f93..7e5fb689b 100644 --- a/web/app/assets/javascripts/session.js +++ b/web/app/assets/javascripts/session.js @@ -94,6 +94,7 @@ var claimedRecording = null; var backing_track_path = null; var jamTrack = null; + var musicianAccessOnJoin; // was this a private or public session when the user tried to joined? var metronomeMixer = null; var playbackControls = null; @@ -211,16 +212,7 @@ rest.getSessionHistory(data.id) .done(function(musicSession) { - var singlePlayerCheckOK = true; - // to know whether we are allowed to be in this session, we have to check if we are the creator when checking against single player functionality - if(musicSession.user_id != context.JK.currentUserId) { - var canPlay = context.JK.guardAgainstSinglePlayerProfile(app, function () { - promptLeave = false; - }); - - singlePlayerCheckOK = canPlay.canPlay; - } - if(singlePlayerCheckOK) { + musicianAccessOnJoin = musicSession.musician_access;; var shouldVerifyNetwork = musicSession.musician_access; gearUtils.guardAgainstInvalidConfiguration(app, shouldVerifyNetwork) @@ -270,17 +262,6 @@ }); }) }) - } - else { - if(canPlay.dialog) { - canPlay.dialog.one(EVENTS.DIALOG_CLOSED, function(e, data) { - if(data.canceled) { - promptLeave = false; - window.location = '/client#/home' - } - }) - } - } }) .fail(function() { @@ -308,188 +289,209 @@ function afterCurrentUserLoaded() { - var sessionModel = context.JK.CurrentSessionModel; - $(sessionModel.recordingModel) + // now check if the user can play in a session with others + var deferred = new $.Deferred(); + if(musicianAccessOnJoin) { + deferred = context.JK.guardAgainstSinglePlayerProfile(app, function () { + promptLeave = false; + }); + } + else { + deferred.resolve(); + } + deferred.fail(function(result) { + if(!result.controlled_location) { + window.location="/client#/home" + } + }) + .done(function() {logger.debug("user has passed all session guards") + promptLeave = true; + var sessionModel = context.JK.CurrentSessionModel; + + $(sessionModel.recordingModel) .on('startingRecording', function(e, data) { - displayStartingRecording(); - lockControlsforJamTrackRecording(); + displayStartingRecording(); + lockControlsforJamTrackRecording(); }) .on('startedRecording', function(e, data) { - if(data.reason) { - var reason = data.reason; - var detail = data.detail; - - var title = "Could Not Start Recording"; - - if(data.reason == 'client-no-response') { - notifyWithUserInfo(title, 'did not respond to the start signal.', detail); - } - else if(data.reason == 'empty-recording-id') { - app.notifyAlert(title, "No recording ID specified."); - } - else if(data.reason == 'missing-client') { - notifyWithUserInfo(title, 'could not be signalled to start recording.', detail); - } - else if(data.reason == 'already-recording') { - app.notifyAlert(title, 'Already recording. If this appears incorrect, try restarting JamKazam.'); - } - else if(data.reason == 'recording-engine-unspecified') { - notifyWithUserInfo(title, 'had a problem writing recording data to disk.', detail); - } - else if(data.reason == 'recording-engine-create-directory') { - notifyWithUserInfo(title, 'had a problem creating a recording folder.', detail); - } - else if(data.reason == 'recording-engine-create-file') { - notifyWithUserInfo(title, 'had a problem creating a recording file.', detail); - } - else if(data.reason == 'recording-engine-sample-rate') { - notifyWithUserInfo(title, 'had a problem recording at the specified sample rate.', detail); - } - else if(data.reason == 'rest') { - var jqXHR = detail[0]; - app.notifyServerError(jqXHR); - } - else { - notifyWithUserInfo(title, 'Error Reason: ' + reason); - } - displayDoneRecording(); - } - else - { - displayStartedRecording(); - displayWhoCreated(data.clientId); - lockControlsforJamTrackRecording(); - } - }) - .on('stoppingRecording', function(e, data) { - displayStoppingRecording(data); - unlockControlsforJamTrackRecording(); - }) - .on('stoppedRecording', function(e, data) { - - unlockControlsforJamTrackRecording(); - if(sessionModel.selfOpenedJamTracks()) { - - var timeline = context.jamClient.GetJamTrackTimeline(); - - rest.addRecordingTimeline(data.recordingId, timeline) - .fail(function(){ - app.notify( - { title: "Unable to Add JamTrack Volume Data", - text: "The volume of the JamTrack will not be correct in the recorded mix." }, - null, - true); - }) - } - - if(data.reason) { - logger.warn("Recording Discarded: ", data); - var reason = data.reason; - var detail = data.detail; - - var title = "Recording Discarded"; - - if(data.reason == 'client-no-response') { - notifyWithUserInfo(title, 'did not respond to the stop signal.', detail); - } - else if(data.reason == 'missing-client') { - notifyWithUserInfo(title, 'could not be signalled to stop recording.', detail); - } - else if(data.reason == 'empty-recording-id') { - app.notifyAlert(title, "No recording ID specified."); - } - else if(data.reason == 'wrong-recording-id') { - app.notifyAlert(title, "Wrong recording ID specified."); - } - else if(data.reason == 'not-recording') { - app.notifyAlert(title, "Not currently recording."); - } - else if(data.reason == 'already-stopping') { - app.notifyAlert(title, "Already stopping the current recording."); - } - else if(data.reason == 'start-before-stop') { - notifyWithUserInfo(title, 'asked that we start a new recording; cancelling the current one.', detail); - } - else { - app.notifyAlert(title, "Error reason: " + reason); - } - - displayDoneRecording(); - } - else { - displayDoneRecording(); - promptUserToSave(data.recordingId, timeline); - } - - }) - .on('abortedRecording', function(e, data) { + if(data.reason) { var reason = data.reason; var detail = data.detail; - var title = "Recording Cancelled"; + var title = "Could Not Start Recording"; if(data.reason == 'client-no-response') { - notifyWithUserInfo(title, 'did not respond to the start signal.', detail); + notifyWithUserInfo(title, 'did not respond to the start signal.', detail); + } + else if(data.reason == 'empty-recording-id') { + app.notifyAlert(title, "No recording ID specified."); } else if(data.reason == 'missing-client') { - notifyWithUserInfo(title, 'could not be signalled to start recording.', detail); + notifyWithUserInfo(title, 'could not be signalled to start recording.', detail); } - else if(data.reason == 'populate-recording-info') { - notifyWithUserInfo(title, 'could not synchronize with the server.', detail); + else if(data.reason == 'already-recording') { + app.notifyAlert(title, 'Already recording. If this appears incorrect, try restarting JamKazam.'); } else if(data.reason == 'recording-engine-unspecified') { - notifyWithUserInfo(title, 'had a problem writing recording data to disk.', detail); + notifyWithUserInfo(title, 'had a problem writing recording data to disk.', detail); } else if(data.reason == 'recording-engine-create-directory') { - notifyWithUserInfo(title, 'had a problem creating a recording folder.', detail); + notifyWithUserInfo(title, 'had a problem creating a recording folder.', detail); } else if(data.reason == 'recording-engine-create-file') { - notifyWithUserInfo(title, 'had a problem creating a recording file.', detail); + notifyWithUserInfo(title, 'had a problem creating a recording file.', detail); } else if(data.reason == 'recording-engine-sample-rate') { - notifyWithUserInfo(title, 'had a problem recording at the specified sample rate.', detail); + notifyWithUserInfo(title, 'had a problem recording at the specified sample rate.', detail); + } + else if(data.reason == 'rest') { + var jqXHR = detail[0]; + app.notifyServerError(jqXHR); } else { - app.notifyAlert(title, "Error reason: " + reason); + notifyWithUserInfo(title, 'Error Reason: ' + reason); + } + displayDoneRecording(); + } + else + { + displayStartedRecording(); + displayWhoCreated(data.clientId); + lockControlsforJamTrackRecording(); + } + }) + .on('stoppingRecording', function(e, data) { + displayStoppingRecording(data); + unlockControlsforJamTrackRecording(); + }) + .on('stoppedRecording', function(e, data) { + + unlockControlsforJamTrackRecording(); + if(sessionModel.selfOpenedJamTracks()) { + + var timeline = context.jamClient.GetJamTrackTimeline(); + + rest.addRecordingTimeline(data.recordingId, timeline) + .fail(function(){ + app.notify( + { title: "Unable to Add JamTrack Volume Data", + text: "The volume of the JamTrack will not be correct in the recorded mix." }, + null, + true); + }) + } + + if(data.reason) { + logger.warn("Recording Discarded: ", data); + var reason = data.reason; + var detail = data.detail; + + var title = "Recording Discarded"; + + if(data.reason == 'client-no-response') { + notifyWithUserInfo(title, 'did not respond to the stop signal.', detail); + } + else if(data.reason == 'missing-client') { + notifyWithUserInfo(title, 'could not be signalled to stop recording.', detail); + } + else if(data.reason == 'empty-recording-id') { + app.notifyAlert(title, "No recording ID specified."); + } + else if(data.reason == 'wrong-recording-id') { + app.notifyAlert(title, "Wrong recording ID specified."); + } + else if(data.reason == 'not-recording') { + app.notifyAlert(title, "Not currently recording."); + } + else if(data.reason == 'already-stopping') { + app.notifyAlert(title, "Already stopping the current recording."); + } + else if(data.reason == 'start-before-stop') { + notifyWithUserInfo(title, 'asked that we start a new recording; cancelling the current one.', detail); + } + else { + app.notifyAlert(title, "Error reason: " + reason); } displayDoneRecording(); + } + else { + displayDoneRecording(); + promptUserToSave(data.recordingId, timeline); + } + + }) + .on('abortedRecording', function(e, data) { + var reason = data.reason; + var detail = data.detail; + + var title = "Recording Cancelled"; + + if(data.reason == 'client-no-response') { + notifyWithUserInfo(title, 'did not respond to the start signal.', detail); + } + else if(data.reason == 'missing-client') { + notifyWithUserInfo(title, 'could not be signalled to start recording.', detail); + } + else if(data.reason == 'populate-recording-info') { + notifyWithUserInfo(title, 'could not synchronize with the server.', detail); + } + else if(data.reason == 'recording-engine-unspecified') { + notifyWithUserInfo(title, 'had a problem writing recording data to disk.', detail); + } + else if(data.reason == 'recording-engine-create-directory') { + notifyWithUserInfo(title, 'had a problem creating a recording folder.', detail); + } + else if(data.reason == 'recording-engine-create-file') { + notifyWithUserInfo(title, 'had a problem creating a recording file.', detail); + } + else if(data.reason == 'recording-engine-sample-rate') { + notifyWithUserInfo(title, 'had a problem recording at the specified sample rate.', detail); + } + else { + app.notifyAlert(title, "Error reason: " + reason); + } + + displayDoneRecording(); }) - sessionModel.subscribe('sessionScreen', sessionChanged); - sessionModel.joinSession(sessionId) + sessionModel.subscribe('sessionScreen', sessionChanged); + + sessionModel.joinSession(sessionId) .fail(function(xhr, textStatus, errorMessage) { - if(xhr.status == 404) { - // we tried to join the session, but it's already gone. kick user back to join session screen - promptLeave = false; - context.window.location = "/client#/findSession"; - app.notify( - { title: "Unable to Join Session", - text: "The session you attempted to join is over." - }, - null, - true); + if(xhr.status == 404) { + // we tried to join the session, but it's already gone. kick user back to join session screen + promptLeave = false; + context.window.location = "/client#/findSession"; + app.notify( + { title: "Unable to Join Session", + text: "The session you attempted to join is over." + }, + null, + true); + } + else if(xhr.status == 422) { + var response = JSON.parse(xhr.responseText); + if(response["errors"] && response["errors"]["tracks"] && response["errors"]["tracks"][0] == "Please select at least one track") { + app.notifyAlert("No Inputs Configured", $('You will need to reconfigure your audio device.')); } - else if(xhr.status == 422) { - var response = JSON.parse(xhr.responseText); - if(response["errors"] && response["errors"]["tracks"] && response["errors"]["tracks"][0] == "Please select at least one track") { - app.notifyAlert("No Inputs Configured", $('You will need to reconfigure your audio device.')); - } - else if(response["errors"] && response["errors"]["music_session"] && response["errors"]["music_session"][0] == ["is currently recording"]) { - promptLeave = false; - context.window.location = "/client#/findSession"; - app.notify( { title: "Unable to Join Session", text: "The session is currently recording." }, null, true); - } - else { - app.notifyServerError(xhr, 'Unable to Join Session'); - } + else if(response["errors"] && response["errors"]["music_session"] && response["errors"]["music_session"][0] == ["is currently recording"]) { + promptLeave = false; + context.window.location = "/client#/findSession"; + app.notify( { title: "Unable to Join Session", text: "The session is currently recording." }, null, true); } else { - app.notifyServerError(xhr, 'Unable to Join Session'); + app.notifyServerError(xhr, 'Unable to Join Session'); } + } + else { + app.notifyServerError(xhr, 'Unable to Join Session'); + } }); + }) + } // not leave session but leave screen @@ -2727,17 +2729,22 @@ // XXX: test with this removed; it should be unnecessary context.jamClient.JamTrackStopPlay(); + var sampleRate = context.jamClient.GetSampleRate() + var sampleRateForFilename = sampleRate == 48 ? '48' : '44' + var fqId = jamTrack.id + '-' + sampleRateForFilename + if(jamTrack.jmep) { logger.debug("setting jmep data") - context.jamClient.JamTrackLoadJmep(jamTrack.id, jamTrack.jmep) + + context.jamClient.JamTrackLoadJmep(fqId, jamTrack.jmep) } else { logger.debug("no jmep data for jamtrack") } // JamTrackPlay means 'load' - var result = context.jamClient.JamTrackPlay(jamTrack.id); + var result = context.jamClient.JamTrackPlay(fqId); if(!result) { app.notify( diff --git a/web/app/assets/javascripts/session_utils.js b/web/app/assets/javascripts/session_utils.js index 4e3b13594..a7eefa791 100644 --- a/web/app/assets/javascripts/session_utils.js +++ b/web/app/assets/javascripts/session_utils.js @@ -136,20 +136,19 @@ return false; } - if(context.JK.guardAgainstSinglePlayerProfile(app).canPlay) { - gearUtils.guardAgainstInvalidConfiguration(app) - .fail(function() { - app.notify( - { title: "Unable to Join Session", - text: "You can only join a session once you have working audio gear and a tested internet connection." - }); - }) - .done(function() { - if (successCallback) { - successCallback(); - } - }); - } + gearUtils.guardAgainstInvalidConfiguration(app) + .fail(function() { + app.notify( + { title: "Unable to Join Session", + text: "You can only join a session once you have working audio gear and a tested internet connection." + }); + }) + .done(function() { + if (successCallback) { + successCallback(); + } + }); + } sessionUtils.joinSession = function(sessionId) { diff --git a/web/app/assets/javascripts/shopping_cart.js b/web/app/assets/javascripts/shopping_cart.js index ac115f175..9de0c7cf2 100644 --- a/web/app/assets/javascripts/shopping_cart.js +++ b/web/app/assets/javascripts/shopping_cart.js @@ -11,7 +11,7 @@ var $content = null; function beforeShow(data) { - + clearContent(); } function afterShow(data) { diff --git a/web/app/assets/javascripts/utils.js b/web/app/assets/javascripts/utils.js index b91ab71af..127b34e62 100644 --- a/web/app/assets/javascripts/utils.js +++ b/web/app/assets/javascripts/utils.js @@ -581,6 +581,7 @@ logger.debug("offBackendEvent: " + alertData.name + '.' + namespace, alertData) $(document).off(alertData.name + '.' + namespace); } + /* * Loads a listbox or dropdown with the values in input_array, setting the option value * to the id_field and the option text to text_field. It will preselect the option with @@ -1125,70 +1126,6 @@ return true; } - context.JK.guardAgainstSinglePlayerProfile = function(app, beforeCallback) { - - var canPlayWithOthers = context.JK.GearUtilsInstance.canPlayWithOthers(); - - if(!canPlayWithOthers.canPlay) { - logger.debug("guarding against single player profile") - - var $dialog = app.layout.showDialog('single-player-profile-dialog'); - - // so that callers can check dialog result - canPlayWithOthers.dialog = $dialog; - - // allow callers to take action before default behavior - if(beforeCallback) { - $dialog.one(EVENTS.DIALOG_CLOSED, beforeCallback); - } - - $dialog.one(EVENTS.DIALOG_CLOSED, function(e, data) { - - if(!data.canceled) { - if(data.result.choice == 'private_session') { - var data = { - createType: 'quick-start', - timezone: {}, - recurring_mode: {}, - language: {}, - band: {}, - musician_access: {}, - fans_access: {}, - rsvp_slots: [], - open_rsvps: false - }; - - context.JK.privateSessionSettings(data) - - context.JK.createSession(app, data) - .done(function(response) { - var sessionId = response.id; - - context.JK.GA.trackSessionCount(true, true, 0); - - // we redirect to the session screen, which handles the REST call to POST /participants. - logger.debug("joining session screen: " + sessionId) - context.location = '/client#/session/' + sessionId; - }) - .fail(function(jqXHR) { - logger.debug("unable to schedule a private session") - app.notifyServerError(jqXHR, "Unable to schedule a private session"); - }) - } - else if(data.result.choice == 'gear_setup') { - window.location = '/client#/account/audio' - } - else - { - logger.error("unknown choice: " + data.result.choice) - alert("unknown choice: " + data.result.choice) - } - } - }) - } - - return canPlayWithOthers; - } context.JK.createSession = function(app, data) { diff --git a/web/app/assets/javascripts/wizard/gear_utils.js b/web/app/assets/javascripts/wizard/gear_utils.js index d5c70d9a1..5629b013b 100644 --- a/web/app/assets/javascripts/wizard/gear_utils.js +++ b/web/app/assets/javascripts/wizard/gear_utils.js @@ -10,6 +10,7 @@ var rest = new context.JK.Rest(); context.JK.GearUtils = gearUtils; var logger = context.JK.logger; + var ALERT_NAMES = context.JK.ALERT_NAMES; var ASSIGNMENT = context.JK.ASSIGNMENT; var VOICE_CHAT = context.JK.VOICE_CHAT; var AUDIO_DEVICE_BEHAVIOR = context.JK.AUDIO_DEVICE_BEHAVIOR; @@ -30,17 +31,39 @@ return channel.assignment == ASSIGNMENT.CHAT || channel.assignment == ASSIGNMENT.OUTPUT || channel.assignment > 0; } + + gearUtils.resyncAudio = function() { + + function backendMixerChange (e, data) { + + if (data.text == 'deferred') { + context.JK.offBackendEvent(ALERT_NAMES.BACKEND_MIXER_CHANGE, 'gearUtilsResyncAudio', backendMixerChange) + console.log("context.jamClient.FTUEGetExpectedLatency()", context.jamClient.FTUEGetExpectedLatency().latency) + deferred.resolve(); + } + ; + } + + var deferred = new $.Deferred(); + + context.JK.onBackendEvent(ALERT_NAMES.BACKEND_MIXER_CHANGE, 'gearUtilsResyncAudio', backendMixerChange); + + context.jamClient.SessionAudioResync(); + + // give backend 5 seconds to timeout + deferred.timer = setTimeout(function() { + deferred.rejectWith('timeout'); + context.JK.offBackendEvent(ALERT_NAMES.BACKEND_MIXER_CHANGE, 'gearUtilsResyncAudio', backendMixerChange) + }, 5000); + + return deferred; + } + + // to play with others, you have to have inputs, // as well have a score below 20 ms gearUtils.canPlayWithOthers = function(profile) { - if(gon.global.gear_check_reload_audio) { - if (!context.jamClient.IsAudioStarted()) { - context.jamClient.ReloadAudioSystem(true, true, true); - context.jamClient.StopAudio(); - } - } - var isNoInputProfile = gearUtils.isNoInputProfile(profile); var expectedLatency = context.jamClient.FTUEGetExpectedLatency(); @@ -431,6 +454,84 @@ return deferred; } + context.JK.guardAgainstSinglePlayerProfile = function(app, beforeCallback) { + + var deferred = new $.Deferred(); + + var canPlayWithOthers = context.JK.GearUtilsInstance.canPlayWithOthers(); + + if(!canPlayWithOthers.canPlay) { + logger.debug("guarding against single player profile") + + var $dialog = app.layout.showDialog('single-player-profile-dialog'); + + // so that callers can check dialog result + canPlayWithOthers.dialog = $dialog; + + // allow callers to take action before default behavior + if(beforeCallback) { + $dialog.one(EVENTS.DIALOG_CLOSED, beforeCallback); + } + + $dialog.one(EVENTS.DIALOG_CLOSED, function(e, data) { + + if(data.canceled) { + deferred.rejectWith(canPlayWithOthers, [{ reason: 'canceled', controlled_location:false }]) + } + else { + if(data.result.choice == 'private_session') { + var data = { + createType: 'quick-start', + timezone: {}, + recurring_mode: {}, + language: {}, + band: {}, + musician_access: {}, + fans_access: {}, + rsvp_slots: [], + open_rsvps: false + }; + + context.JK.privateSessionSettings(data) + + context.JK.createSession(app, data) + .done(function(response) { + var sessionId = response.id; + + context.JK.GA.trackSessionCount(true, true, 0); + + deferred.rejectWith(canPlayWithOthers, [{ reason: 'private_session', controlled_location:true }]) + // we redirect to the session screen, which handles the REST call to POST /participants. + logger.debug("joining session screen: " + sessionId) + context.location = '/client#/session/' + sessionId; + }) + .fail(function(jqXHR) { + deferred.rejectWith(canPlayWithOthers, [{ reason: 'gear_setup', controlled_location:false }]) + logger.debug("unable to schedule a private session") + app.notifyServerError(jqXHR, "Unable to schedule a private session"); + }) + } + else if(data.result.choice == 'gear_setup') { + deferred.rejectWith(canPlayWithOthers, [{ reason: data.result.choice,controlled_location:true }]) + window.location = '/client#/account/audio' + } + else + { + deferred.rejectWith(canPlayWithOthers, [{ reason: 'unknown', controlled_location:false }]) + logger.error("unknown choice: " + data.result.choice) + alert("unknown choice: " + data.result.choice) + } + } + }) + } + else { + deferred.resolveWith(canPlayWithOthers) + } + + + return deferred; + } + gearUtils.guardAgainstActiveProfileMissing = function (app, backendInfo) { diff --git a/web/app/assets/stylesheets/playbackControls.css.scss b/web/app/assets/stylesheets/playbackControls.css.scss index a1e20c77f..2dcfb5b0f 100644 --- a/web/app/assets/stylesheets/playbackControls.css.scss +++ b/web/app/assets/stylesheets/playbackControls.css.scss @@ -1,3 +1,4 @@ +// see audioWidgets.css .recording-controls { diff --git a/web/app/controllers/api_jam_tracks_controller.rb b/web/app/controllers/api_jam_tracks_controller.rb index f7dbc3b18..399410554 100644 --- a/web/app/controllers/api_jam_tracks_controller.rb +++ b/web/app/controllers/api_jam_tracks_controller.rb @@ -7,6 +7,10 @@ class ApiJamTracksController < ApiController respond_to :json + def log + @log || Logging.logger[ApiJamTracksController] + end + def show @jam_track = JamTrack.find_by_plan_code!(params[:plan_code]) end @@ -70,7 +74,7 @@ class ApiJamTracksController < ApiController def download if @jam_track_right.valid? sample_rate = params[:sample_rate].nil? ? nil : params[:sample_rate].to_i - if (@jam_track_right && @jam_track_right.ready?(sample_rate)) + if @jam_track_right && @jam_track_right.ready?(sample_rate) @jam_track_right.update_download_count @jam_track_right.last_downloaded_at = Time.now @jam_track_right.save! @@ -86,7 +90,8 @@ class ApiJamTracksController < ApiController def enqueue sample_rate = params[:sample_rate].nil? ? nil : params[:sample_rate].to_i - @jam_track_right.enqueue_if_needed(sample_rate) + enqueued = @jam_track_right.enqueue_if_needed(sample_rate) + log.debug("jamtrack #{enqueued ? "ENQUEUED" : "NOT ENQUEUED"}: jam_track_right=#{@jam_track_right.id} sample_rate=#{sample_rate} ") render :json => { :message => "enqueued" }, :status => 200 end @@ -102,14 +107,31 @@ class ApiJamTracksController < ApiController return end - jamtrack_ids = jamtrack_holder[:tracks] + jamtracks = jamtrack_holder[:tracks] - unless jamtrack_ids.kind_of?(Array) + unless jamtracks.kind_of?(Array) render :json => {message: 'jamtracks:tracks parameter must be an array'}, :status => 422 return end + + # jamtracks come in the form id-44 or id-48, so we need to do a little extra parsing + puts "#{jamtracks.inspect}" + jamtrack_ids = Set.new + jamtracks_fq_ids = Set.new + jamtracks.each do |jamtrack| + rindex = jamtrack.rindex('-') + if rindex + id = jamtrack[0..(rindex-1)] + jamtrack_ids << id + jamtracks_fq_ids << jamtrack # includes sample rate + end + end + + + puts "#{jamtrack_ids.inspect} #{jamtracks_fq_ids.inspect}" @jam_tracks = JamTrackRight.list_keys(current_user, jamtrack_ids) + @jamtracks_fq_ids = jamtracks_fq_ids end private diff --git a/web/app/views/api_jam_tracks/keys.rabl b/web/app/views/api_jam_tracks/keys.rabl index f82aa5650..a5cd9d471 100644 --- a/web/app/views/api_jam_tracks/keys.rabl +++ b/web/app/views/api_jam_tracks/keys.rabl @@ -1,9 +1,23 @@ object @jam_tracks node do |jam_track| -{ - id: jam_track['id'].to_s, - private: jam_track['private_key'], - error: jam_track['private_key'] ? nil : ( jam_track['jam_track_right_id'] ? 'no_key' : 'not_purchased' ) -} + + id = jam_track['id'] + result = { id: id } + + if @jamtracks_fq_ids.include?("#{id}-44") + result['44'] = { + private: jam_track['private_key_44'], + error: jam_track['private_key_44'] ? nil : ( jam_track['jam_track_right_id'] ? 'no_key' : 'not_purchased' ) + } + end + + if @jamtracks_fq_ids.include?("#{id}-48") + result['48'] = { + private: jam_track['private_key_48'], + error: jam_track['private_key_48'] ? nil : ( jam_track['jam_track_right_id'] ? 'no_key' : 'not_purchased' ) + } + end + + result end \ No newline at end of file diff --git a/web/config/application.rb b/web/config/application.rb index 9a21433ce..ad3aff3e3 100644 --- a/web/config/application.rb +++ b/web/config/application.rb @@ -332,6 +332,5 @@ if defined?(Bundler) config.alerts_api_enabled = true config.gear_check_ignore_high_latency = false - config.gear_check_reload_audio = true end end diff --git a/web/config/initializers/gon.rb b/web/config/initializers/gon.rb index f9eb797f6..ff5a4d74f 100644 --- a/web/config/initializers/gon.rb +++ b/web/config/initializers/gon.rb @@ -14,5 +14,4 @@ Gon.global.recurly_public_api_key = Rails.application.config.recurly_public_api_ Gon.global.one_free_jamtrack_per_user = Rails.application.config.one_free_jamtrack_per_user Gon.global.video_available = Rails.application.config.video_available Gon.global.gear_check_ignore_high_latency = Rails.application.config.gear_check_ignore_high_latency -Gon.global.gear_check_reload_audio = Rails.application.config.gear_check_reload_audio Gon.global.env = Rails.env diff --git a/web/spec/controllers/api_jam_tracks_controller_spec.rb b/web/spec/controllers/api_jam_tracks_controller_spec.rb index e70578564..123041120 100644 --- a/web/spec/controllers/api_jam_tracks_controller_spec.rb +++ b/web/spec/controllers/api_jam_tracks_controller_spec.rb @@ -143,30 +143,33 @@ describe ApiJamTracksController do end it "download depends on rights" do - get :download, :id=>@jam_track.id + get :download, :id=>@jam_track.id, sample_rate: 48 response.status.should == 403 right = JamTrackRight.create(:user=>@user, :jam_track=>@jam_track) - get :download, :id=>@jam_track.id + get :download, :id=>@jam_track.id, sample_rate: 48 response.status.should == 202 right.download_count.should eq(0) - right.private_key.should be_nil + right.private_key_44.should be_nil + right.private_key_48.should be_nil qname = "#{ResqueSpec.queue_name(JamRuby::JamTracksBuilder)}" #puts "ResqueSpec.peek(qname)#{ResqueSpec.peek(qname)}" - JamTracksBuilder.should have_queued(right.id,nil).in(:jam_tracks_builder) + JamTracksBuilder.should have_queued(right.id,48).in(:jam_tracks_builder) expect(ResqueSpec.peek(qname).present?).to eq(true) ResqueSpec.perform_next(qname) JamTracksBuilder.should_not have_queued(right.id,nil).in(:jam_tracks_builder) right.reload - right.private_key.should_not be_nil + right.private_key_44.should be_nil + right.private_key_48.should_not be_nil right.download_count.should eq(0) - get :download, :id=>@jam_track.id + get :download, :id=>@jam_track.id, sample_rate: 48 response.status.should == 302 - response.location.should =~ /.*#{Regexp.escape(right.filename)}.*/ + puts response.location + response.location.should =~ /.*#{Regexp.escape(right.filename(:url_48))}.*/ right.reload right.download_count.should eq(1) @@ -182,7 +185,8 @@ describe ApiJamTracksController do get :download, :id=>@jam_track.id, :sample_rate=>44 response.status.should == 202 right.download_count.should eq(0) - right.private_key.should be_nil + right.private_key_44.should be_nil + right.private_key_48.should be_nil qname = "#{ResqueSpec.queue_name(JamRuby::JamTracksBuilder)}" #puts "ResqueSpec.peek(qname)#{ResqueSpec.peek(qname)}" @@ -193,12 +197,13 @@ describe ApiJamTracksController do JamTracksBuilder.should_not have_queued(right.id, 44).in(:jam_tracks_builder) right.reload - right.private_key.should_not be_nil + right.private_key_44.should_not be_nil + right.private_key_48.should be_nil right.download_count.should eq(0) get :download, :id=>@jam_track.id, :sample_rate=>44 response.status.should == 302 - response.location.should =~ /.*#{Regexp.escape(right.filename)}.*/ + response.location.should =~ /.*#{Regexp.escape(right.filename(:url_44))}.*/ right.reload right.download_count.should eq(1) @@ -216,53 +221,66 @@ describe ApiJamTracksController do end it "track with no rights" do - get :keys, jamtracks: { tracks: [@jam_track.id] } + get :keys, jamtracks: { tracks: ["#{@jam_track.id}-44"] } response.status.should == 200 json = JSON.parse(response.body) json.length.should == 1 json[0]['id'].should == @jam_track.id.to_s - json[0]['private'].should be_nil - json[0]['error'].should == 'not_purchased' + json[0]['44'].should_not be_nil + json[0]['44']['private'].should be_nil + json[0]['44']['error'].should == 'not_purchased' + json[0]['48'].should be_nil end it "track with no key" do - right = FactoryGirl.create(:jam_track_right, user: @user, private_key: nil, jam_track: @jam_track) + right = FactoryGirl.create(:jam_track_right, user: @user, private_key_44: nil, private_key_48:nil, jam_track: @jam_track) - get :keys, jamtracks: { tracks: [@jam_track.id] } + get :keys, jamtracks: { tracks: ["#{@jam_track.id}-44", "#{@jam_track.id}-48"] } response.status.should == 200 json = JSON.parse(response.body) json.length.should == 1 - json[0]['id'].should == @jam_track.id.to_s - json[0]['private'].should be_nil - json[0]['error'].should == 'no_key' + json[0]['44'].should_not be_nil + json[0]['44']['private'].should be_nil + json[0]['44']['error'].should == 'no_key' + json[0]['48'].should_not be_nil + json[0]['48']['private'].should be_nil + json[0]['48']['error'].should == 'no_key' end it "track with key" do - right = FactoryGirl.create(:jam_track_right, user: @user, private_key: 'abc', jam_track: @jam_track) - get :keys, jamtracks: { tracks: [@jam_track.id] } + right = FactoryGirl.create(:jam_track_right, user: @user, private_key_44: 'abc', private_key_48:nil, jam_track: @jam_track) + get :keys, jamtracks: { tracks: ["#{@jam_track.id}-44", "#{@jam_track.id}-48"] } response.status.should == 200 json = JSON.parse(response.body) json.length.should == 1 json[0]['id'].should == @jam_track.id.to_s - json[0]['private'].should eq('abc') - json[0]['error'].should be_nil + json[0]['44'].should_not be_nil + json[0]['44']['private'].should eq('abc') + json[0]['44']['error'].should be_nil + json[0]['48'].should_not be_nil + json[0]['48']['private'].should be_nil + json[0]['48']['error'].should == 'no_key' end it "non-owning user asking for a real track" do - right = FactoryGirl.create(:jam_track_right, user: FactoryGirl.create(:user), private_key: 'abc', jam_track: @jam_track) - get :keys, jamtracks: { tracks: [@jam_track.id] } + right = FactoryGirl.create(:jam_track_right, user: FactoryGirl.create(:user), private_key_44: 'abc', private_key_48:nil, jam_track: @jam_track) + get :keys, jamtracks: { tracks: ["#{@jam_track.id}-44", "#{@jam_track.id}-48"] } response.status.should == 200 json = JSON.parse(response.body) json[0]['id'].should == @jam_track.id.to_s - json[0]['private'].should be_nil - json[0]['error'].should == 'not_purchased' + json[0]['44'].should_not be_nil + json[0]['44']['private'].should be_nil + json[0]['44']['error'].should eq('not_purchased') + json[0]['48'].should_not be_nil + json[0]['48']['private'].should be_nil + json[0]['48']['error'].should eq('not_purchased') end end describe "enqueue" do it "success" do - right = FactoryGirl.create(:jam_track_right, user: @user, signed: false) + right = FactoryGirl.create(:jam_track_right, user: @user, signed_44: false, signed_48:false) right.signing_queued_at.should be_nil post :enqueue, {:format=>'json', :id=>right.jam_track.id} response.should be_success diff --git a/web/spec/features/jamtrack_shopping_spec.rb b/web/spec/features/jamtrack_shopping_spec.rb index 4dd20a058..4273067ce 100644 --- a/web/spec/features/jamtrack_shopping_spec.rb +++ b/web/spec/features/jamtrack_shopping_spec.rb @@ -135,11 +135,15 @@ describe "JamTrack Shopping", :js => true, :type => :feature, :capybara_feature find_jamtrack jt_us find("a.jamtrack-add-cart[data-jamtrack-id=\"#{jt_us.id}\"]").trigger(:click) - find('a.button-orange', text: 'CONTINUE SHOPPING').trigger(:click) - find("a.jamtrack-add-cart[data-jamtrack-id=\"#{jt_ww.id}\"]").trigger(:click) + find('.shopping-sub-total', text: "Subtotal:$ #{jt_us.price}") find('a.button-orange', text: 'CONTINUE SHOPPING').trigger(:click) - find('.shopping-sub-total', text: "Subtotal: $ #{jt_us.price + jt_ww.price}") + find_jamtrack jt_ww + + find("a.jamtrack-add-cart[data-jamtrack-id=\"#{jt_ww.id}\"]").trigger(:click) + find('.shopping-sub-total', text: "Subtotal:$ #{jt_us.price + jt_ww.price}") + #find('a.button-orange', text: 'CONTINUE SHOPPING').trigger(:click) + end it "can expand" do