From 9bce6964bded29a3a23ef9a197a687631ae4ab75 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Fri, 11 Sep 2015 12:53:00 -0500 Subject: [PATCH] * wip --- db/up/mixdown.sql | 4 +- pb/src/client_container.proto | 4 +- ruby/lib/jam_ruby/lib/subscription_message.rb | 14 +- ruby/lib/jam_ruby/models/jam_track_mixdown.rb | 2 +- ruby/lib/jam_ruby/models/notification.rb | 7 +- .../resque/jam_track_mixdown_packager.rb | 22 +-- .../javascripts/dialog/openJamTrackDialog.js | 3 +- web/app/assets/javascripts/fakeJamClient.js | 5 + .../PopupMediaControls.js.jsx.coffee | 158 +++++++++++++++++- .../stores/JamTrackMixdownStore.js.coffee | 32 +++- web/app/assets/javascripts/utils.js | 18 ++ .../minimal/media_controls.css.scss | 75 +++++++++ web/config/routes.rb | 6 +- 13 files changed, 314 insertions(+), 36 deletions(-) diff --git a/db/up/mixdown.sql b/db/up/mixdown.sql index cc048ae55..164c410a4 100644 --- a/db/up/mixdown.sql +++ b/db/up/mixdown.sql @@ -43,4 +43,6 @@ CREATE TABLE jam_track_mixdown_packages ( updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); -ALTER TABLE jam_track_rights ADD COLUMN last_mixdown_id VARCHAR(64) REFERENCES jam_track_mixdowns(id) ON DELETE SET NULL; \ No newline at end of file +ALTER TABLE jam_track_rights ADD COLUMN last_mixdown_id VARCHAR(64) REFERENCES jam_track_mixdowns(id) ON DELETE SET NULL; + +ALTER TABLE notifications ADD COLUMN jam_track_mixdown_package_id VARCHAR(64) REFERENCES jam_track_mixdown_packages(id) ON DELETE CASCADE; \ No newline at end of file diff --git a/pb/src/client_container.proto b/pb/src/client_container.proto index 14a8215c4..4acccc86d 100644 --- a/pb/src/client_container.proto +++ b/pb/src/client_container.proto @@ -621,11 +621,11 @@ message JamTrackSignFailed { } message MixdownSignComplete { - required int32 mixdown_package_id = 1; // jam track mixdown package id + required string mixdown_package_id = 1; // jam track mixdown package id } message MixdownSignFailed { - required int32 mixdown_package_id = 1; // jam track mixdown package id + required string mixdown_package_id = 1; // jam track mixdown package id } diff --git a/ruby/lib/jam_ruby/lib/subscription_message.rb b/ruby/lib/jam_ruby/lib/subscription_message.rb index dc1636b5e..02b98f3b9 100644 --- a/ruby/lib/jam_ruby/lib/subscription_message.rb +++ b/ruby/lib/jam_ruby/lib/subscription_message.rb @@ -14,19 +14,25 @@ module JamRuby end def self.mount_source_up_requested(mount) - Notification.send_subscription_message('mount', mount.id, {change_type: IcecastSourceChange::CHANGE_TYPE_MOUNT_UP_REQUEST}.to_json ) + Notification.send_subscription_message('mount', mount.id, {change_type: IcecastSourceChange::CHANGE_TYPE_MOUNT_UP_REQUEST}.to_json) end def self.mount_source_down_requested(mount) - Notification.send_subscription_message('mount', mount.id, {change_type: IcecastSourceChange::CHANGE_TYPE_MOUNT_DOWN_REQUEST}.to_json ) + Notification.send_subscription_message('mount', mount.id, {change_type: IcecastSourceChange::CHANGE_TYPE_MOUNT_DOWN_REQUEST}.to_json) end def self.jam_track_signing_job_change(jam_track_right) - Notification.send_subscription_message('jam_track_right', jam_track_right.id.to_s, {signing_state: jam_track_right.signing_state, current_packaging_step: jam_track_right.current_packaging_step, packaging_steps: jam_track_right.packaging_steps}.to_json ) + Notification.send_subscription_message('jam_track_right', jam_track_right.id.to_s, + {signing_state: jam_track_right.signing_state, + current_packaging_step: jam_track_right.current_packaging_step, + packaging_steps: jam_track_right.packaging_steps}.to_json) end def self.mixdown_signing_job_change(jam_track_mixdown_package) - Notification.send_subscription_message('mixdown', jam_track_mixdown_package.id.to_s, {signing_state: jam_track_mixdown_package.signing_state, current_packaging_step: jam_track_mixdown_package.current_packaging_step, packaging_steps: jam_track_right.packaging_steps}.to_json ) + Notification.send_subscription_message('mixdown', jam_track_mixdown_package.id.to_s, + {signing_state: jam_track_mixdown_package.signing_state, + current_packaging_step: jam_track_mixdown_package.current_packaging_step, + packaging_steps: jam_track_mixdown_package.packaging_steps}.to_json) end def self.test diff --git a/ruby/lib/jam_ruby/models/jam_track_mixdown.rb b/ruby/lib/jam_ruby/models/jam_track_mixdown.rb index 62947f0db..13af25332 100644 --- a/ruby/lib/jam_ruby/models/jam_track_mixdown.rb +++ b/ruby/lib/jam_ruby/models/jam_track_mixdown.rb @@ -16,7 +16,7 @@ module JamRuby validates :jam_track, presence: true validates :settings, presence: true - validates_uniqueness_of :user_id, scope: :jam_track_id + validates_uniqueness_of :name, scope: :user_id validate :verify_settings diff --git a/ruby/lib/jam_ruby/models/notification.rb b/ruby/lib/jam_ruby/models/notification.rb index 0bfc4da4b..d86d73d12 100644 --- a/ruby/lib/jam_ruby/models/notification.rb +++ b/ruby/lib/jam_ruby/models/notification.rb @@ -14,6 +14,7 @@ module JamRuby belongs_to :music_session, :class_name => "JamRuby::MusicSession", :foreign_key => "music_session_id" belongs_to :recording, :class_name => "JamRuby::Recording", :foreign_key => "recording_id" belongs_to :jam_track_right, :class_name => "JamRuby::JamTrackRight", :foreign_key => "jam_track_right_id" + belongs_to :jam_track_mixdown_package, :class_name => "JamRuby::JamTrackMixdownPackage", :foreign_key => "jam_track_mixdown_package_id" validates :target_user, :presence => true validates :message, length: {minimum: 1, maximum: 400}, no_profanity: true, if: :text_message? @@ -1255,7 +1256,7 @@ module JamRuby def send_jam_track_sign_complete(jam_track_right) notification = Notification.new - notification.jam_track_right_id = jam_track_right.id + notification.jam_track_mixdown_package = jam_track_right.id notification.description = NotificationTypes::JAM_TRACK_SIGN_COMPLETE notification.target_user_id = jam_track_right.user_id notification.save! @@ -1268,7 +1269,7 @@ module JamRuby def send_mixdown_sign_failed(jam_track_mixdown_package) notification = Notification.new - notification.jam_track_right_id = jam_track_mixdown_package.id + notification.jam_track_mixdown_package_id = jam_track_mixdown_package.id notification.description = NotificationTypes::MIXDOWN_SIGN_FAILED notification.target_user_id = jam_track_mixdown_package.jam_track_mixdown.user_id notification.save! @@ -1280,7 +1281,7 @@ module JamRuby def send_mixdown_sign_complete(jam_track_mixdown_package) notification = Notification.new - notification.mixdown_package_id = jam_track_mixdown_package.id + notification.jam_track_mixdown_package_id = jam_track_mixdown_package.id notification.description = NotificationTypes::MIXDOWN_SIGN_COMPLETE notification.target_user_id = jam_track_mixdown_package.jam_track_mixdown.user_id notification.save! diff --git a/ruby/lib/jam_ruby/resque/jam_track_mixdown_packager.rb b/ruby/lib/jam_ruby/resque/jam_track_mixdown_packager.rb index 3afe04816..097c3f32a 100644 --- a/ruby/lib/jam_ruby/resque/jam_track_mixdown_packager.rb +++ b/ruby/lib/jam_ruby/resque/jam_track_mixdown_packager.rb @@ -5,7 +5,7 @@ require 'net/http' require 'digest/md5' module JamRuby - class JamTracksMixdownPackager + class JamTrackMixdownPackager extend JamRuby::ResqueStats include JamRuby::S3ManagerMixin @@ -14,26 +14,26 @@ module JamRuby MAX_PAN = 90 MIN_PAN = -90 - attr_accessor :mixdown_package_id, :settings, :mixdown_package, :mixdown, :steps + attr_accessor :mixdown_package_id, :settings, :mixdown_package, :mixdown, :step @queue = :jam_track_mixdown_packager def log - @log || Logging.logger[JamTracksMixdownPackager] + @log || Logging.logger[JamTrackMixdownPackager] end def self.perform(mixdown_package_id, bitrate=48) - jam_track_builder = JamTracksMixdownPackager.new() + jam_track_builder = JamTrackMixdownPackager.new() jam_track_builder.mixdown_package_id = mixdown_package_id jam_track_builder.run end def compute_steps - @steps = 0 + @step = 0 number_downloads = @track_settings.length - number_volume_adjustments = @track_settings.select { |track| should_alter_volume? track } + number_volume_adjustments = (@track_settings.select { |track| should_alter_volume? track }).length pitch_shift_steps = @mixdown.will_pitch_shift? ? 1 : 0 - mix_step = 1 + mix_steps = 1 package_steps = 1 number_downloads + number_volume_adjustments + pitch_shift_steps + mix_steps + package_steps @@ -379,7 +379,7 @@ module JamRuby # set @error_reason before you raise an exception, and it will be sent back as the error reason # otherwise, the error_reason will be unhandled-job-exception def post_error(e) - begin + #begin # if error_reason is null, assume this is an unhandled error unless @error_reason @error_reason = "unhandled-job-exception" @@ -387,9 +387,9 @@ module JamRuby end @mixdown_package.finish_errored(@error_reason, @error_detail) - rescue Exception => e - log.error "unable to post back to the database the error #{e}" - end + #rescue Exception => e + # log.error "unable to post back to the database the error #{e}" + #end end end end diff --git a/web/app/assets/javascripts/dialog/openJamTrackDialog.js b/web/app/assets/javascripts/dialog/openJamTrackDialog.js index 8f58b0728..ed400d8c1 100644 --- a/web/app/assets/javascripts/dialog/openJamTrackDialog.js +++ b/web/app/assets/javascripts/dialog/openJamTrackDialog.js @@ -103,9 +103,8 @@ sampleRate = context.jamClient.GetSampleRate() sampleRateForFilename = sampleRate == 48 ? '48' : '44'; doSearch(); - - } + function afterHide() { showing = false; } diff --git a/web/app/assets/javascripts/fakeJamClient.js b/web/app/assets/javascripts/fakeJamClient.js index 464f992b8..53faafc14 100644 --- a/web/app/assets/javascripts/fakeJamClient.js +++ b/web/app/assets/javascripts/fakeJamClient.js @@ -117,6 +117,10 @@ return 30; } + function GetSampleRate() { + return 48; + } + function isSessVideoShared() { return videoShared; } @@ -1262,6 +1266,7 @@ this.FTUESetSendFrameRates = FTUESetSendFrameRates; this.GetCurrentVideoResolution = GetCurrentVideoResolution; this.GetCurrentVideoFrameRate = GetCurrentVideoFrameRate; + this.GetSampleRate = GetSampleRate; this.isSessVideoShared = isSessVideoShared; this.SessStopVideoSharing = SessStopVideoSharing; diff --git a/web/app/assets/javascripts/react-components/PopupMediaControls.js.jsx.coffee b/web/app/assets/javascripts/react-components/PopupMediaControls.js.jsx.coffee index f2e0a127a..0887a8143 100644 --- a/web/app/assets/javascripts/react-components/PopupMediaControls.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/PopupMediaControls.js.jsx.coffee @@ -18,6 +18,7 @@ if accessOpener SessionActions = window.opener.SessionActions MediaPlaybackStore = window.opener.MediaPlaybackStore MixerActions = window.opener.MixerActions + JamTrackMixdownActions = window.opener.JamTrackMixdownActions JamTrackMixdownStore = window.opener.JamTrackMixdownStore JamTrackMixdown = window.opener.JamTrackMixdown MixerStore = window.opener.MixerStore @@ -66,7 +67,7 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged')) SessionActions.showNativeMetronomeGui() getInitialState: () -> - {media: @props.media, time: '0:00', mixdown: @props.mixdown, jamTrack: @props.jamTrack} + {media: @props.media, time: '0:00', mixdown: @props.mixdown, jamTrack: @props.jamTrack, creatingMixdown: false, createMixdownErrors: null} close: () -> window.close() @@ -107,20 +108,120 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged')) {customMixName} ` - myMixes = [] + myMixes = null if @state.showMyMixes - logger.debug("show my mixes") + myMixdowns = [] + for mixdown in jamTrack.mixdowns + myMixdowns.push << ` +
+ {mixdown.name} +
` - mixControls = [] + myMixes = `
{myMixdowns}
` + + mixControls = null if @state.showCustomMixes - logger.debug("show mix controls") + + + nameClassData = {field: true} + if @state.createMixdownErrors? + + errorHtml = context.JK.reactErrors(@state.createMixdownErrors, {name: 'Mix Name'}) + console.log("errorHtml", errorHtml) + + createMixClasses = classNames({'button-orange' : true, 'create-mix-btn' : true, 'disabled' : @state.creatingMixdown}) + mixControls = ` +
+

Use the JamTrack controls on the session screen to set levels, mute/unmute, or pan any of the parts of the JamTrack as you like. You can also use the controls below to adjust the tempo or pitch of the JamTrack. Then give your custom mix a name, and click the Create Mix button. Please note that changing the tempo or pitch of the JamTrack may take a long time, and won't be ready right away.

+
+ + +
+
+ + +
+
+ + +
+
+ CREATE MIX + {errorHtml} +
+
+ +
` + + + if @state.showMyMixes + showMyMixesText = 'hide my mixes' + else + showMyMixesText = 'show my mixes' + + if @state.showCustomMixes + showMixControlsText = 'hide mix controls' + else + showMixControlsText = 'show mix controls' extraControls = `
-

My Mixes show my mixes

+

My Mixes {showMyMixesText}

{myMixes} -

Create Custom Mix show mix controls

+

Create Custom Mix {showMixControlsText}

{mixControls}
` @@ -165,6 +266,49 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged')) e.preventDefault() @setState({showCustomMixes: !@state.showCustomMixes}) + createMix: (e) -> + e.preventDefault() + + return if @state.creatingMix + + $root = $(@getDOMNode()) + + name = $root.find('input[name="mix-name"]').val() + speed = $root.find('select[name="mix-speed"]').val() + pitch = $root.find('select[name="mix-pitch"]').val() + + logger.debug("NAME", name) + if name == null || name == '' + @setState({createMixdownErrors: {errors: {'Mix Name': ["can't be blank"]}}}) + return + + # sanitize junk out of speed/pitch + if speed == '' || speed.indexOf('separator') > -1 + speed = undefined + if pitch == '' || pitch.indexOf('separator') > -1 + pitch = undefined + + + mixdown = {jamTrackID: @state.jamTrack.id, name: name, settings: {speed:speed, pitch: pitch}} + + package_settings = {file_type: 'ogg', encrypt_type: 'jkz'} + + JamTrackMixdownActions.create(mixdown, package_settings, @createMixdownDone, @createMixdownFail) + + @setState({creatingMixdown: true, createMixdownErrors: null}) + + createMixdownDone: (created) -> + logger.debug("created (within PopupMediaControls)", created) + @setState({creatingMixdown: false}) + + createMixdownFail: (jqXHR) -> + logger.debug("create mixdown fail (within PopupMediaControls)", jqXHR.status) + @setState({creatingMixdown: false}) + if jqXHR.status == 422 + response = JSON.parse(jqXHR.responseText) + logger.warn("failed to create mixdown", response, jqXHR.responseText) + + @setState({createMixdownErrors: response}) componentDidMount: () -> diff --git a/web/app/assets/javascripts/react-components/stores/JamTrackMixdownStore.js.coffee b/web/app/assets/javascripts/react-components/stores/JamTrackMixdownStore.js.coffee index caf3ae0c0..02ac78e82 100644 --- a/web/app/assets/javascripts/react-components/stores/JamTrackMixdownStore.js.coffee +++ b/web/app/assets/javascripts/react-components/stores/JamTrackMixdownStore.js.coffee @@ -21,10 +21,13 @@ JamTrackActions = @JamTrackActions current: null init: () -> + this.listenTo(context.AppStore, this.onAppInit); this.listenTo(context.JamTrackStore, this.onJamTrackChanged); @changed() + onAppInit: (@app) -> + getState: () -> @state @@ -35,8 +38,33 @@ JamTrackActions = @JamTrackActions onJamTrackChanged: (@jamTrack) -> # TODO: close out building? current? - onCreate: (mixdown) -> - logger.debug("creating mixdown", mixdown) + onCreate: (mixdown, package_settings, done, fail) -> + logger.debug("creating mixdown", mixdown, package_settings) + rest.createMixdown(mixdown) + .done((created) => + + logger.debug("created mixdown", created) + + package_settings.id = created.id + + # we have to determine sample rate here, in the store, because child windows don't have access to jamClient + sampleRate = context.jamClient.GetSampleRate() + sampleRate = if sampleRate == 48 then 48 else 44 + package_settings.sample_rate = sampleRate + + rest.enqueueMixdown(package_settings) + .done((enqueued) => + logger.debug("enqueued mixdown package", package_settings) + done(enqueued) + ) + .fail((jqxhr) => + @app.layout.notify({title:'Unable to Package Mixdown', text: 'You can push the RETRY button.'}) + fail(jqxhr) + ) + ) + .fail((jqxhr) => + fail(jqxhr) + ) onEdit: (mixdown) -> logger.debug("editing mixdown", mixdown) diff --git a/web/app/assets/javascripts/utils.js b/web/app/assets/javascripts/utils.js index fed60372a..5dfcbde51 100644 --- a/web/app/assets/javascripts/utils.js +++ b/web/app/assets/javascripts/utils.js @@ -921,6 +921,24 @@ return ul; } + context.JK.reactErrors = function (errors_data, fieldMapper) { + var errors = errors_data["errors"]; + if (errors == null) return null; + var items = [] + + $.each(errors, function (fieldName, field_errors) { + var displayName = fieldMapper && fieldMapper[fieldName] + if (!displayName) { + displayName = fieldName; + } + $.each(field_errors, function (index, item) { + items.push(React.DOM.li({key: fieldName + item}, displayName + ' ' + item)) + }); + }); + + return React.DOM.ul({className: 'error-text'}, null, items) + } + /** * Way to verify that a number of parallel tasks have all completed. diff --git a/web/app/assets/stylesheets/minimal/media_controls.css.scss b/web/app/assets/stylesheets/minimal/media_controls.css.scss index 84ea7564b..919cfd411 100644 --- a/web/app/assets/stylesheets/minimal/media_controls.css.scss +++ b/web/app/assets/stylesheets/minimal/media_controls.css.scss @@ -36,6 +36,7 @@ body.media-controls-popup.popup { .close-link { margin-top:20px; font-size:11px; + margin-bottom:10px; } .display-metronome { @@ -44,9 +45,83 @@ body.media-controls-popup.popup { } .header { + padding-bottom:20px; h3 { text-align:center; font-weight:bold; } + + h4 { + margin-top:15px; + font-size:12px; + font-weight:normal; + } + + h5 { + font-size:12px; + font-weight:normal; + } + } + + .extra-controls { + margin-top:20px; + h4 { + text-align:left; + font-size:14px; + a { + font-size:11px; + position:absolute; + right:20px; + } + &.custom-mix-header { + margin-top:20px; + } + } + + .create-mix { + margin-top:5px; + border-color:$ColorTextTypical; + border-style: solid; + border-width:1px 0; + padding: 7px 0 20px; + + p { + line-height:125%; + color:$ColorTextTypical; + text-align:left; + font-size:12px; + } + + .field { + display:block; + height:25px; + margin-top:15px; + } + + ul.error-text { + float:right; + display:block !important; + color: red; + margin-top: 5px; + } + + a.create-mix-btn { + margin-top:15px; + float:right; + margin-right: 2px; + margin-top: 3px; + } + label { + display:inline; + float:left; + } + + select, input { + width:170px; + float:right; + @include border_box_sizing; + background-color:$ColorTextBoxBackground; + } + } } } \ No newline at end of file diff --git a/web/config/routes.rb b/web/config/routes.rb index 9122eca13..196b368f9 100644 --- a/web/config/routes.rb +++ b/web/config/routes.rb @@ -250,11 +250,11 @@ SampleApp::Application.routes.draw do # mixdowns match '/jamtracks/:id/mixdowns' => 'api_jam_track_mixdowns#index', :via => :get - match '/mixdowns' => 'api_jam_track_mixdowns#create', :via => :post + match '/mixdowns/:id/download' => 'api_jam_track_mixdowns#download', :via => :get + match '/mixdowns/:id/enqueue' => 'api_jam_track_mixdowns#enqueue', :via => :post match '/mixdowns/:id' => 'api_jam_track_mixdowns#show', :via => :get match '/mixdowns/:id' => 'api_jam_track_mixdowns#update', :via => :post - match '/mixdowns/:id/download' => 'api_jam_track_mixdowns#download', :via => :get - match '/mixdowns/:id/enqueue' => 'api_jam_track_mixdowns#enqueue', :via => :get + match '/mixdowns' => 'api_jam_track_mixdowns#create', :via => :post match '/mixdown_packages/:id' => 'api_jam_track_mixdowns#show_package', :via => :get # Shopping carts