diff --git a/admin/app/admin/jam_tracks.rb b/admin/app/admin/jam_tracks.rb index ac1897c4e..96f341829 100644 --- a/admin/app/admin/jam_tracks.rb +++ b/admin/app/admin/jam_tracks.rb @@ -25,7 +25,6 @@ ActiveAdmin.register JamRuby::JamTrack, :as => 'JamTracks' do column :original_artist column :name column :status - column :preview do |jam_track| jam_track.has_preview? ? (link_to "Download", jam_track.sign_url(3600)) : 'None' end column :master_track do |jam_track| jam_track.master_track.nil? ? 'None' : (link_to "Download", jam_track.master_track.url_by_sample_rate(44)) end column :licensor column :genre diff --git a/admin/app/views/admin/jam_tracks/_form.html.slim b/admin/app/views/admin/jam_tracks/_form.html.slim index b74dba9c1..fc0d9502a 100644 --- a/admin/app/views/admin/jam_tracks/_form.html.slim +++ b/admin/app/views/admin/jam_tracks/_form.html.slim @@ -4,7 +4,6 @@ = f.input :name, :input_html => { :rows=>1, :maxlength=>200 } = f.input :description, :input_html => { :rows=>5, :maxlength=>1000 } = f.input :plan_code, :label=>'Recurly Plan Code', :required=>true, :hint => 'Must match plan code in Recurly' - = f.input :version, :label => 'Version', :hint => 'Increment this value whenever you invalidate (update) the media in the JamTrack. Changing JMEP does not count as a version change; changing anything about a track (audio, instrument, part) does.' //= f.input :initial_play_silence, :label => 'Initial Play Silence (seconds)' = f.input :time_signature, collection: JamRuby::JamTrack::TIME_SIGNATURES, include_blank: true = f.input :status, collection: JamRuby::JamTrack::STATUS, include_blank: false, hint: 'Only set to Production when end users should be able to purchase this JamTrack' @@ -23,15 +22,11 @@ = f.input :public_performance_royalty, :label => 'Public Performance Royalty' = f.input :reproduction_royalty_amount, :required=>true, :input_html=>{type:'numeric'} = f.input :licensor_royalty_amount, :required=>true, :input_html=>{type:'numeric'} - = f.input :preview_start_time_raw, :label=>'Preview Start Time', :hint => 'MM:SS:MLS', :as => :string - - unless f.object.nil? || f.object[:preview_url].nil? - .current_file_holder style='margin-bottom:10px' - a href=f.object.sign_url(3600) style='padding:0 0 0 20px' - | Download //= f.input :url, :as => :file, :label => 'Audio File' = f.input :jmep_text, :as => :text, :label => "JMEP Text", :input_html => {:rows => 5 }, :hint => 'Tap-Ins & Lead Silence. Examples: https://jamkazam.atlassian.net/wiki/pages/viewpage.action?pageId=39289025#JamKazamMeta-EventProcessor(JMEP)-CommonExamples' = f.input :jmep_json, :as => :text, :label => "JMEP Json", :input_html => {:rows => 5, :readonly => true }, :hint => 'Readonly field. This is shown here just so you can see what your JMEP got converted to readily' + = f.input :version, :label => 'Version', :hint => 'Increment this value whenever you invalidate (update) the media in the JamTrack. Changing JMEP does not count as a version change; changing anything about a track (audio, instrument, part) does.' = f.semantic_fields_for :jam_track_tracks do |track| = render 'jam_track_track_fields', f: track diff --git a/admin/app/views/admin/jam_tracks/_jam_track_track_fields.html.slim b/admin/app/views/admin/jam_tracks/_jam_track_track_fields.html.slim index 593d8ef7d..c08812dcb 100644 --- a/admin/app/views/admin/jam_tracks/_jam_track_track_fields.html.slim +++ b/admin/app/views/admin/jam_tracks/_jam_track_track_fields.html.slim @@ -4,8 +4,12 @@ = f.input :track_type, :as => :select, collection: ['Track', 'Master'], include_blank: false = f.input :instrument, collection: Instrument.all, include_blank: false = f.input :part, :required=>true, :input_html => { :rows=>1, :maxlength=>20, :type=>'numeric' } - = f.input :position + = f.input :preview_start_time_raw, :label => 'Preview Start Time', :hint => 'MM:SS:MLS', :as => :string + - unless f.object.nil? || f.object[:preview_url].nil? + .current_file_holder style='margin-bottom:10px' + a href=f.object.preview_sign_url(3600) style='padding:0 0 0 20px' + | Download Preview - if f.object.new_record? p style='margin-left:10px' @@ -16,12 +20,12 @@ - unless f.object.nil? || f.object[:url_48].nil? .current_file_holder style='margin-bottom:10px' a href=f.object.sign_url(3600) style='padding:0 0 0 20px' - | Download + | #{File.basename(f.object[:url_48])} = f.input :url_44, :as => :file, :label => 'Track file (44kHz)' - unless f.object.nil? || f.object[:url_44].nil? .current_file_holder style='margin-bottom:10px' a href=f.object.sign_url(3600, 44) style='padding:0 0 0 20px' - | Download + | #{File.basename(f.object[:url_44])} = link_to_remove_association "Delete Track", f, class: 'button', style: 'margin-left:10px' \ No newline at end of file diff --git a/admin/config/initializers/jam_track_tracks.rb b/admin/config/initializers/jam_track_tracks.rb new file mode 100644 index 000000000..dde477bad --- /dev/null +++ b/admin/config/initializers/jam_track_tracks.rb @@ -0,0 +1,101 @@ +class JamRuby::JamTrackTrack + + # add a custom validation + + attr_accessor :preview_generate_error + + validate :preview + + def preview + if preview_generate_error + errors.add(:preview_start_time, preview_generate_error) + end + end + + + + # this is used by active admin/jam-admin + def preview_start_time_raw + if self.preview_start_time.nil? || self.preview_start_time.nil? + '' + else + seconds = self.preview_start_time.to_f/1000 + time = Time.at(seconds) + time.strftime("%M:%S:#{(self.preview_start_time % 1000).to_s.rjust(3, '0')}") + end + end + + # this is used by active admin/jam-admin + def preview_start_time_raw=(new_value) + + value = nil + if new_value == nil || new_value == '' + value = nil + else + if new_value && new_value.kind_of?(String) && new_value.include?(':') + bits = new_value.split(':') + if bits.length != 3 + raise "format of preview start time must be MM:SS:MLS" + end + + value = (bits[0].to_i * 60000) + (bits[1].to_i * 1000) + (bits[2].to_i) + + else + raise "format of preview start time must be MM:SS:MLS" + end + end + + if !value.nil? && value != self.preview_start_time + self.preview_start_time = value + generate_preview + else + self.preview_start_time = value + end + end + + def generate_preview + + begin + Dir.mktmpdir do |tmp_dir| + + input = File.join(tmp_dir, 'in.ogg') + output = File.join(tmp_dir, 'out.ogg') + + start = self.preview_start_time.to_f / 1000 + stop = start + 20 + + raise 'no track' unless self["url_44"] + + s3_manager.download(self.url_by_sample_rate(44), input) + + command = "sox \"#{input}\" \"#{output}\" trim #{start} #{stop}" + + @@log.debug("trimming using: " + command) + + sox_output = `#{command}` + + result_code = $?.to_i + + if result_code != 0 + @@log.debug("fail #{result_code}") + @preview_generate_error = "unable to execute cut command #{sox_output}" + else + @@log.debug("uploading preview to #{self.preview_filename}") + + s3_manager.upload(self.preview_filename, output) + + # and finally update the JamTrackTrack with the new info + self["preview_url"] = self.preview_filename + self["preview_md5"] = ::Digest::MD5.file(output).hexdigest + self["preview_length"] = File.new(output).size + self.save! + end + end + rescue Exception => e + @@log.error("error in sox command #{e.to_s}") + @preview_generate_error = e.to_s + end + + end + +end diff --git a/admin/config/initializers/jam_tracks.rb b/admin/config/initializers/jam_tracks.rb index c1c0063bf..cd02eccee 100644 --- a/admin/config/initializers/jam_tracks.rb +++ b/admin/config/initializers/jam_tracks.rb @@ -6,7 +6,6 @@ class JamRuby::JamTrack before_save :jmep_json_generate validate :jmep_text_validate - validate :preview def jmep_text_validate begin @@ -28,97 +27,4 @@ class JamRuby::JamTrack #errors.add(:jmep_text, err.to_s) end end - - def preview - if preview_generate_error - errors.add(:preview_url, preview_generate_error) - end - end - - - - # this is used by active admin/jam-admin - def preview_start_time_raw - if self.preview_start_time.nil? || self.preview_start_time.nil? - '' - else - seconds = self.preview_start_time.to_f/1000 - time = Time.at(seconds) - time.strftime("%M:%S:#{(self.preview_start_time % 1000).to_s.rjust(3, '0')}") - end - end - - # this is used by active admin/jam-admin - def preview_start_time_raw=(new_value) - - value = nil - if new_value == nil || new_value == '' - value = nil - else - if new_value && new_value.kind_of?(String) && new_value.include?(':') - bits = new_value.split(':') - if bits.length != 3 - raise "format of preview start time must be MM:SS:MLS" - end - - value = (bits[0].to_i * 60000) + (bits[1].to_i * 1000) + (bits[2].to_i) - - else - raise "format of preview start time must be MM:SS:MLS" - end - end - - if !value.nil? && value != self.preview_start_time - self.preview_start_time = value - generate_preview - else - self.preview_start_time = value - end - end - - def generate_preview - - begin - Dir.mktmpdir do |tmp_dir| - - input = File.join(tmp_dir, 'in.ogg') - output = File.join(tmp_dir, 'out.ogg') - - start = self.preview_start_time.to_f / 1000 - stop = start + 20 - - master_track = self.master_track - - raise 'no master track' unless master_track - - s3_manager.download(master_track.url_by_sample_rate(44), input) - - command = "sox \"#{input}\" \"#{output}\" trim #{start} #{stop}" - - @@log.debug("trimming using: " + command) - - sox_output = `#{command}` - - result_code = $?.to_i - - if result_code != 0 - @preview_generate_error = "unable to execute cut command #{sox_output}" - else - @@log.debug("uploading preview to #{self.preview_filename}") - - s3_manager.upload(self.preview_filename, output) - - # and finally update the JamTrackTrack with the new info - self["preview_url"] = self.preview_filename - self["preview_md5"] = ::Digest::MD5.file(output).hexdigest - self["preview_length"] = File.new(output).size - self.save! - end - end - rescue Exception => e - @preview_generate_error = e.to_s - end - - end - end diff --git a/db/manifest b/db/manifest index 0d02da16b..791afb9d9 100755 --- a/db/manifest +++ b/db/manifest @@ -262,4 +262,5 @@ jam_track_importer.sql jam_track_pro_licensing_update.sql jam_track_redeemed.sql connection_metronome.sql +preview_jam_track_tracks.sql cohorts.sql diff --git a/db/up/preview_jam_track_tracks.sql b/db/up/preview_jam_track_tracks.sql new file mode 100644 index 000000000..a8c9ae224 --- /dev/null +++ b/db/up/preview_jam_track_tracks.sql @@ -0,0 +1,9 @@ +ALTER TABLE jam_tracks DROP COLUMN preview_url; +ALTER TABLE jam_tracks DROP COLUMN preview_md5; +ALTER TABLE jam_tracks DROP COLUMN preview_length; +ALTER TABLE jam_tracks DROP COLUMN preview_start_time; + +ALTER TABLE jam_track_tracks ADD COLUMN preview_url VARCHAR; +ALTER TABLE jam_track_tracks ADD COLUMN preview_md5 VARCHAR; +ALTER TABLE jam_track_tracks ADD COLUMN preview_length BIGINT; +ALTER TABLE jam_track_tracks ADD COLUMN preview_start_time INTEGER; \ No newline at end of file diff --git a/ruby/lib/jam_ruby/models/jam_track.rb b/ruby/lib/jam_ruby/models/jam_track.rb index 47efe3cdf..058e44d1e 100644 --- a/ruby/lib/jam_ruby/models/jam_track.rb +++ b/ruby/lib/jam_ruby/models/jam_track.rb @@ -17,7 +17,7 @@ module JamRuby :original_artist, :songwriter, :publisher, :licensor, :licensor_id, :pro, :genre, :genre_id, :sales_region, :price, :reproduction_royalty, :public_performance_royalty, :reproduction_royalty_amount, :licensor_royalty_amount, :pro_royalty_amount, :plan_code, :initial_play_silence, :jam_track_tracks_attributes, - :jam_track_tap_ins_attributes, :version, :jmep_json, :jmep_text, :pro_ascap, :pro_bmi, :pro_sesac, :preview_start_time_raw, as: :admin + :jam_track_tap_ins_attributes, :version, :jmep_json, :jmep_text, :pro_ascap, :pro_bmi, :pro_sesac, as: :admin validates :name, presence: true, uniqueness: true, length: {maximum: 200} validates :plan_code, presence: true, uniqueness: true, length: {maximum: 50 } @@ -31,7 +31,6 @@ module JamRuby validates :sales_region, inclusion: {in: [nil] + SALES_REGION} validates_format_of :price, with: /^\d+\.*\d{0,2}$/ validates :version, presence: true - validates :preview_start_time, numericality: {only_integer: true}, length: {in: 1..1000}, :allow_nil => true validates :pro_ascap, inclusion: {in: [true, false]} validates :pro_bmi, inclusion: {in: [true, false]} validates :pro_sesac, inclusion: {in: [true, false]} @@ -92,21 +91,6 @@ module JamRuby end end - # create name of the file - def preview_filename - "jam_track_previews/#{self.original_artist}/#{self.name}/preview-44100.ogg" - end - - def has_preview? - !self["preview_url"].nil? - end - # creates a short-lived URL that has access to the object. - # the idea is that this is used when a user who has the rights to this tries to download this JamTrack - # we would verify their rights (can_download?), and generates a URL in response to the click so that they can download - # but the url is short lived enough so that it wouldn't be easily shared - def sign_url(expiration_time = 120) - s3_manager.sign_url(self[:preview_url], {:expires => expiration_time, :response_content_type => 'audio/ogg', :secure => false}) - end def master_track JamTrackTrack.where(jam_track_id: self.id).where(track_type: 'Master').first diff --git a/ruby/lib/jam_ruby/models/jam_track_track.rb b/ruby/lib/jam_ruby/models/jam_track_track.rb index 255cd0337..71ba7fea8 100644 --- a/ruby/lib/jam_ruby/models/jam_track_track.rb +++ b/ruby/lib/jam_ruby/models/jam_track_track.rb @@ -7,17 +7,21 @@ module JamRuby # there should only be one Master per JamTrack, but there can be N Track per JamTrack TRACK_TYPE = %w{Track Master} + @@log = Logging.logger[JamTrackTrack] + + mount_uploader :url_48, JamTrackTrackUploader mount_uploader :url_44, JamTrackTrackUploader attr_accessible :jam_track_id, :track_type, :instrument, :instrument_id, :position, :part, as: :admin - attr_accessible :url_44, :url_48, :md5_44, :md5_48, :length_44, :length_48, as: :admin + attr_accessible :url_44, :url_48, :md5_44, :md5_48, :length_44, :length_48, :preview_start_time_raw, as: :admin attr_accessor :original_audio_s3_path, :skip_uploader validates :position, presence: true, numericality: {only_integer: true}, length: {in: 1..1000} validates :part, length: {maximum: 25} validates :track_type, inclusion: {in: TRACK_TYPE } + validates :preview_start_time, numericality: {only_integer: true}, length: {in: 1..1000}, :allow_nil => true validates_uniqueness_of :position, scope: :jam_track_id validates_uniqueness_of :part, scope: [:jam_track_id, :instrument_id] # validates :jam_track, presence: true @@ -37,6 +41,24 @@ module JamRuby "#{store_dir}/#{jam_track.original_artist}/#{jam_track.name}/#{original_name}" end + # create name of the file + def preview_filename + filename("#{File.basename(self["url_44"], ".ogg")}-preview.ogg") + end + + def has_preview? + !self["preview_url"].nil? + end + + # creates a short-lived URL that has access to the object. + # the idea is that this is used when a user who has the rights to this tries to download this JamTrack + # we would verify their rights (can_download?), and generates a URL in response to the click so that they can download + # but the url is short lived enough so that it wouldn't be easily shared + def preview_sign_url(expiration_time = 120) + s3_manager.sign_url(self[:preview_url], {:expires => expiration_time, :response_content_type => 'audio/ogg', :secure => false}) + end + + def manually_uploaded_filename(mounted_as) if track_type == 'Master' filename("Master Mix-#{mounted_as == :url_48 ? '48000' : '44100'}.ogg") diff --git a/web/app/assets/javascripts/networkTestHelper.js b/web/app/assets/javascripts/networkTestHelper.js index c295f1123..61273a2db 100644 --- a/web/app/assets/javascripts/networkTestHelper.js +++ b/web/app/assets/javascripts/networkTestHelper.js @@ -26,6 +26,7 @@ var TEST_TIMEOUT_CALLBACK = 'JK.HandleNetworkTestTimeout'; var $startNetworkTestBtn = null; + var $foreverNetworkTestBtn = null; var $testResults = null; var $testScore = null; var $testText = null; @@ -51,6 +52,8 @@ var operatingSystem = null; var PRIME_PUMP_TIME = 1; + var forever = false; + // these try to make it such that we only pass a NetworkTest Pass/Failed one time in a new user flow var trackedPass = false; var lastNetworkFailure = null; @@ -313,6 +316,9 @@ if (success) { $self.triggerHandler(NETWORK_TEST_DONE) + if(forever) { + prepareNetworkTest(); + } } else { $self.triggerHandler(NETWORK_TEST_FAIL) @@ -875,6 +881,7 @@ inGearWizard = _inGearWizard; $startNetworkTestBtn = $step.find('.start-network-test'); + $foreverNetworkTestBtn = $step.find('.forever-network-test') if ($startNetworkTestBtn.length == 0) throw 'no start network test button found in network-test' @@ -889,8 +896,16 @@ $subscore = $step.find('.subscore'); $watchVideo = $step.find('.watch-video'); $startNetworkTestBtn.on('click', function () { + forever = false; prepareNetworkTest(); }); + if(context.JK.currentUserAdmin) { + $foreverNetworkTestBtn.on('click', function() { + forever = true; + prepareNetworkTest(); + }).show(); + } + operatingSystem = context.JK.GetOSAsString(); initializeVideoWatchButton(); diff --git a/web/app/assets/stylesheets/client/wizard/gearWizard.css.scss b/web/app/assets/stylesheets/client/wizard/gearWizard.css.scss index 29d498f69..6916f7c60 100644 --- a/web/app/assets/stylesheets/client/wizard/gearWizard.css.scss +++ b/web/app/assets/stylesheets/client/wizard/gearWizard.css.scss @@ -342,6 +342,11 @@ margin-top: 20px; } + a.forever-network-test { + margin-top:20px; + display:none; + } + .network-test-score { height: 24px; padding: 10px; diff --git a/web/app/views/clients/_network_test.html.haml b/web/app/views/clients/_network_test.html.haml index a61e4e081..0a2e34d64 100644 --- a/web/app/views/clients/_network_test.html.haml +++ b/web/app/views/clients/_network_test.html.haml @@ -16,6 +16,8 @@ %p Then click on the Start Network Test button below. .center %a.button-orange.start-network-test{href:'#'} START NETWORK TEST + %br + %a.button-orange.forever-network-test{href:'#'} THE FOREVER TEST (ADMIN ONLY) .wizard-step-column %h2 Test Results .network-test-results.ftue-box