This commit is contained in:
Seth Call 2015-09-11 12:53:00 -05:00
parent 544ab4539e
commit 9bce6964bd
13 changed files with 314 additions and 36 deletions

View File

@ -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;
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;

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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!

View File

@ -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

View File

@ -103,9 +103,8 @@
sampleRate = context.jamClient.GetSampleRate()
sampleRateForFilename = sampleRate == 48 ? '48' : '44';
doSearch();
}
function afterHide() {
showing = false;
}

View File

@ -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;

View File

@ -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}
</div>`
myMixes = []
myMixes = null
if @state.showMyMixes
logger.debug("show my mixes")
myMixdowns = []
for mixdown in jamTrack.mixdowns
myMixdowns.push << `
<div key={mixdown.id} className="mixdown">
{mixdown.name}
</div>`
mixControls = []
myMixes = `<div className="my-mixes">{myMixdowns}</div>`
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 = `
<div className="create-mix">
<p>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.</p>
<div className="field">
<label>Change Tempo:</label>
<select name="mix-speed">
<option value="">No change</option>
<option value="separator-1">------------</option>
<option value="-5">Slower by 5%</option>
<option value="-10">Slower by 10%</option>
<option value="-15">Slower by 15%</option>
<option value="-20">Slower by 20%</option>
<option value="-25">Slower by 25%</option>
<option value="-30">Slower by 30%</option>
<option value="-35">Slower by 35%</option>
<option value="-40">Slower by 40%</option>
<option value="-45">Slower by 45%</option>
<option value="-50">Slower by 50%</option>
<option value="-60">Slower by 60%</option>
<option value="-70">Slower by 70%</option>
<option value="-80">Slower by 80%</option>
<option value="separator-2">------------</option>
<option value="5">Faster by 5%</option>
<option value="10">Faster by 10%</option>
<option value="15">Faster by 15%</option>
<option value="20">Faster by 20%</option>
<option value="30">Faster by 30%</option>
<option value="40">Faster by 40%</option>
<option value="50">Faster by 50%</option>
</select>
</div>
<div className="field">
<label>Change Pitch:</label>
<select name="mix-pitch">
<option value="">No change</option>
<option value="separator-1">---------------</option>
<option value="-1">Down 1 Semitone</option>
<option value="-2">Down 2 Semitones</option>
<option value="-3">Down 3 Semitones</option>
<option value="-4">Down 4 Semitones</option>
<option value="-5">Down 5 Semitones</option>
<option value="-6">Down 6 Semitones</option>
<option value="-7">Down 7 Semitones</option>
<option value="-8">Down 8 Semitones</option>
<option value="-9">Down 9 Semitones</option>
<option value="-10">Down 10 Semitones</option>
<option value="-11">Down 11 Semitones</option>
<option value="-12">Down 12 Semitones</option>
<option value="separator-2">---------------</option>
<option value="1">Up 1 Semitone</option>
<option value="2">Up 2 Semitones</option>
<option value="3">Up 3 Semitones</option>
<option value="4">Up 4 Semitones</option>
<option value="5">Up 5 Semitones</option>
<option value="6">Up 6 Semitones</option>
<option value="7">Up 7 Semitones</option>
<option value="8">Up 8 Semitones</option>
<option value="9">Up 9 Semitones</option>
<option value="10">Up 10 Semitones</option>
<option value="11">Up 11 Semitones</option>
<option value="12">Up 12 Semitones</option>
</select>
</div>
<div className={classNames(nameClassData)}>
<label>Mix Name:</label>
<input type="text" name="mix-name"/>
</div>
<div className="field">
<a className={createMixClasses} onClick={this.createMix}>CREATE MIX</a>
{errorHtml}
</div>
<div className="clearall"/>
</div>`
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 = `
<div className="extra-controls">
<h4>My Mixes <a onClick={this.toggleMyMixes}>show my mixes</a></h4>
<h4>My Mixes <a onClick={this.toggleMyMixes}>{showMyMixesText}</a></h4>
{myMixes}
<h4>Create Custom Mix <a onClick={this.toggleCustomMixes}>show mix controls</a></h4>
<h4 className="custom-mix-header">Create Custom Mix <a onClick={this.toggleCustomMixes}>{showMixControlsText}</a></h4>
{mixControls}
</div>`
@ -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: () ->

View File

@ -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)

View File

@ -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.

View File

@ -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;
}
}
}
}

View File

@ -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