Merge
This commit is contained in:
parent
38cc681817
commit
0f1c436f60
|
|
@ -126,6 +126,8 @@ module JamAdmin
|
|||
config.twitter_app_secret = ENV['TWITTER_APP_SECRET'] || 'Azcy3QqfzYzn2fsojFPYXcn72yfwa0vG6wWDrZ3KT8'
|
||||
|
||||
config.ffmpeg_path = ENV['FFMPEG_PATH'] || (File.exist?('/usr/local/bin/ffmpeg') ? '/usr/local/bin/ffmpeg' : '/usr/bin/ffmpeg')
|
||||
config.normalize_ogg_path = ENV['NORMALIZE_OGG_PATH'] || (File.exist?('/usr/local/bin/normalize-ogg') ? '/usr/local/bin/normalize-ogg' : '/usr/bin/normalize-ogg')
|
||||
config.normalize_mp3_path = ENV['NORMALIZE_MP3_PATH'] || (File.exist?('/usr/local/bin/normalize-mp3') ? '/usr/local/bin/normalize-mp3' : '/usr/bin/normalize-mp3')
|
||||
|
||||
config.max_audio_downloads = 100
|
||||
|
||||
|
|
|
|||
|
|
@ -481,6 +481,7 @@ message RecordingMasterMixComplete {
|
|||
optional string msg = 3;
|
||||
optional string notification_id = 4;
|
||||
optional string created_at = 5;
|
||||
optional string claimed_recording_id = 6;
|
||||
}
|
||||
|
||||
message DownloadAvailable {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@ module JamRuby
|
|||
"#{base_url}/findSession"
|
||||
end
|
||||
|
||||
def self.session(session)
|
||||
"#{base_url}/session/#{session.id}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.base_url
|
||||
|
|
|
|||
|
|
@ -712,9 +712,10 @@ module JamRuby
|
|||
)
|
||||
end
|
||||
|
||||
def recording_master_mix_complete(receiver_id, recording_id, band_id, msg, notification_id, created_at)
|
||||
def recording_master_mix_complete(receiver_id, recording_id, claimed_recording_id, band_id, msg, notification_id, created_at)
|
||||
recording_master_mix_complete = Jampb::RecordingMasterMixComplete.new(
|
||||
:recording_id => recording_id,
|
||||
:claimed_recording_id => claimed_recording_id,
|
||||
:band_id => band_id,
|
||||
:msg => msg,
|
||||
:notification_id => notification_id,
|
||||
|
|
|
|||
|
|
@ -1147,6 +1147,7 @@ module JamRuby
|
|||
msg = @@message_factory.recording_master_mix_complete(
|
||||
claimed_recording.user_id,
|
||||
recording.id,
|
||||
claimed_recording.id,
|
||||
notification.band_id,
|
||||
notification_msg,
|
||||
notification.id,
|
||||
|
|
|
|||
|
|
@ -322,7 +322,7 @@ module JamRuby
|
|||
|
||||
raise "no output ogg file after mix" unless File.exist? @output_ogg_filename
|
||||
|
||||
ffmpeg_cmd = "#{APP_CONFIG.ffmpeg_path} -i \"#{@output_ogg_filename}\" -ab 128k -metadata JamRecordingId=#{@manifest[:recording_id]} -metadata JamMixId=#{@mix_id} -metadata JamType=Mix \"#{@output_mp3_filename}\""
|
||||
ffmpeg_cmd = "#{APP_CONFIG.ffmpeg_path} -i \"#{@output_ogg_filename}\" -ab 192k -metadata JamRecordingId=#{@manifest[:recording_id]} -metadata JamMixId=#{@mix_id} -metadata JamType=Mix \"#{@output_mp3_filename}\""
|
||||
|
||||
system(ffmpeg_cmd)
|
||||
|
||||
|
|
@ -335,6 +335,30 @@ module JamRuby
|
|||
end
|
||||
|
||||
raise "no output mp3 file after conversion" unless File.exist? @output_mp3_filename
|
||||
|
||||
# time to normalize both mp3 and ogg files
|
||||
|
||||
normalize_ogg_cmd = "#{APP_CONFIG.normalize_ogg_path} --bitrate 128 -i \"#{@output_ogg_filename}\""
|
||||
system(normalize_ogg_cmd)
|
||||
unless $? == 0
|
||||
@error_reason = 'normalize-ogg-failed'
|
||||
@error_detail = $?.to_s
|
||||
error_msg = "normalize-ogg failed status=#{$?} error_reason=#{@error_reason} error_detail=#{@error_detail}"
|
||||
@@log.info(error_msg)
|
||||
raise error_msg
|
||||
end
|
||||
raise "no output ogg file after normalization" unless File.exist? @output_ogg_filename
|
||||
|
||||
normalize_mp3_cmd = "#{APP_CONFIG.normalize_mp3_path} --bitrate 128 -i \"#{@output_mp3_filename}\""
|
||||
system(normalize_mp3_cmd)
|
||||
unless $? == 0
|
||||
@error_reason = 'normalize-mp3-failed'
|
||||
@error_detail = $?.to_s
|
||||
error_msg = "normalize-mp3 failed status=#{$?} error_reason=#{@error_reason} error_detail=#{@error_detail}"
|
||||
@@log.info(error_msg)
|
||||
raise error_msg
|
||||
end
|
||||
raise "no output mp3 file after conversion" unless File.exist? @output_mp3_filename
|
||||
end
|
||||
|
||||
def symbolize_keys(obj)
|
||||
|
|
|
|||
|
|
@ -38,6 +38,14 @@ def app_config
|
|||
ENV['FFMPEG_PATH'] || '/usr/local/bin/ffmpeg'
|
||||
end
|
||||
|
||||
def normalize_ogg_path
|
||||
ENV['NORMALIZE_OGG_PATH'] || '/usr/local/bin/normalize-ogg'
|
||||
end
|
||||
|
||||
def normalize_mp3_path
|
||||
ENV['NORMALIZE_MP3_PATH'] || '/usr/local/bin/normalize-mp3'
|
||||
end
|
||||
|
||||
def icecast_reload_cmd
|
||||
'true' # as in, /bin/true
|
||||
end
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
var notificationBatchSize = 20;
|
||||
var currentNotificationPage = 0;
|
||||
var didLoadAllNotifications = false, isLoading = false;
|
||||
var ui = new context.JK.UIHelper(JK.app);
|
||||
|
||||
function isNotificationsPanelVisible() {
|
||||
return $contents.is(':visible')
|
||||
|
|
@ -1101,7 +1102,7 @@
|
|||
"class": "button-orange",
|
||||
callback: shareRecording,
|
||||
callback_args: {
|
||||
"recording_id": payload.recording_id
|
||||
"claimed_recording_id": payload.claimed_recording_id
|
||||
}
|
||||
}]
|
||||
);
|
||||
|
|
@ -1109,7 +1110,9 @@
|
|||
}
|
||||
|
||||
function shareRecording(args) {
|
||||
var recordingId = args.recording_id;
|
||||
var claimedRecordingId = args.claimed_recording_id;
|
||||
|
||||
ui.launchShareDialog(claimedRecordingId, 'recording');
|
||||
}
|
||||
|
||||
function registerBandInvitation() {
|
||||
|
|
|
|||
|
|
@ -84,17 +84,25 @@ class RecordingUtils
|
|||
mixStateClass = 'discarded'
|
||||
mixState = 'discarded'
|
||||
else
|
||||
mixStateMsg = 'STILL UPLOADING'
|
||||
mixStateClass = 'still-uploading'
|
||||
mixState = 'still-uploading'
|
||||
|
||||
return {
|
||||
if mix.fake and mix.discarded
|
||||
mixStateMsg = 'DISCARDED'
|
||||
mixStateClass = 'discarded'
|
||||
mixState = 'discarded'
|
||||
else
|
||||
mixStateMsg = 'STILL UPLOADING'
|
||||
mixStateClass = 'still-uploading'
|
||||
mixState = 'still-uploading'
|
||||
|
||||
result = {
|
||||
mixStateMsg: mixStateMsg,
|
||||
mixStateClass: mixStateClass,
|
||||
mixState: mixState,
|
||||
isError: mixState == 'error'
|
||||
}
|
||||
|
||||
result
|
||||
|
||||
onMixHover: () ->
|
||||
$mix = $(this).closest('.mix')
|
||||
mixStateInfo = $mix.data('mix-state')
|
||||
|
|
@ -114,7 +122,10 @@ class RecordingUtils
|
|||
serverInfo = $mix.data('server-info')
|
||||
|
||||
# lie if this is a virtualized mix (i.e., mix is created after recording is made)
|
||||
mixState = 'still-uploading' if !serverInfo? or serverInfo.fake
|
||||
if !serverInfo?
|
||||
mixState = 'still-uploading'
|
||||
else if serverInfo.fake
|
||||
mixState = if serverInfo.discarded then 'discarded' else 'still-uploading'
|
||||
|
||||
summary = ''
|
||||
if mixState == 'still-uploading'
|
||||
|
|
|
|||
|
|
@ -371,6 +371,14 @@
|
|||
if(response["errors"] && response["errors"]["tracks"] && response["errors"]["tracks"][0] == "Please select at least one track") {
|
||||
app.notifyAlert("No Inputs Configured", $('<span>You will need to reconfigure your audio device.</span>'));
|
||||
}
|
||||
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 {
|
||||
app.notifyServerError(xhr, 'Unable to Join Session');
|
||||
|
|
@ -396,7 +404,12 @@
|
|||
if(screenActive) {
|
||||
// this path is possible if FTUE is invoked on session page, and they cancel
|
||||
sessionModel.leaveCurrentSession()
|
||||
.fail(app.ajaxError);
|
||||
.fail(function(jqXHR) {
|
||||
if(jqXHR.status != 404) {
|
||||
logger.debug("leave session failed");
|
||||
app.ajaxError(arguments)
|
||||
}
|
||||
});
|
||||
}
|
||||
screenActive = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -184,10 +184,10 @@
|
|||
leaveSessionRest(currentSessionId)
|
||||
.done(function() {
|
||||
sessionChanged();
|
||||
deferred.resolve(arguments);
|
||||
deferred.resolve(arguments[0], arguments[1], arguments[2]);
|
||||
})
|
||||
.fail(function() {
|
||||
deferred.reject(arguments);
|
||||
deferred.reject(arguments[0], arguments[1], arguments[2]);
|
||||
});
|
||||
|
||||
// 'unregister' for callbacks
|
||||
|
|
|
|||
|
|
@ -133,6 +133,11 @@
|
|||
rest.getSession(sessionId)
|
||||
.done(function(response) {
|
||||
session = response;
|
||||
if(session && session.recording) {
|
||||
context.JK.app.notify( { title: "Unable to Join Session", text: "The session is currently recording." }, null, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if ("invitations" in session) {
|
||||
var invitation;
|
||||
// user has invitations for this session
|
||||
|
|
|
|||
|
|
@ -220,6 +220,7 @@ context.JK.SyncViewer = class SyncViewer
|
|||
updateTrackState: ($track) =>
|
||||
clientInfo = $track.data('client-info')
|
||||
serverInfo = $track.data('server-info')
|
||||
myTrack = serverInfo.user.id == context.JK.currentUserId
|
||||
|
||||
# determine client state
|
||||
clientStateMsg = 'UNKNOWN'
|
||||
|
|
@ -261,7 +262,7 @@ context.JK.SyncViewer = class SyncViewer
|
|||
uploadStateClass = 'error'
|
||||
uploadState = @uploadStates.too_many_upload_failures
|
||||
else
|
||||
if serverInfo.user.id == context.JK.currentUserId
|
||||
if myTrack
|
||||
if clientInfo?
|
||||
if clientInfo.local_state == 'HQ'
|
||||
uploadStateMsg = 'PENDING UPLOAD'
|
||||
|
|
@ -282,7 +283,7 @@ context.JK.SyncViewer = class SyncViewer
|
|||
else
|
||||
uploadStateMsg = 'UPLOADED'
|
||||
uploadStateClass = 'uploaded'
|
||||
if serverInfo.user.id == context.JK.currentUserId
|
||||
if myTrack
|
||||
uploadState = @uploadStates.me_uploaded
|
||||
else
|
||||
uploadState = @uploadStates.them_uploaded
|
||||
|
|
@ -301,6 +302,30 @@ context.JK.SyncViewer = class SyncViewer
|
|||
$uploadStateMsg.text(uploadStateMsg)
|
||||
$uploadStateProgress.css('width', '0')
|
||||
|
||||
# this allows us to make styling decisions based on the combination of both client and upload state.
|
||||
$track.addClass("clientState-#{clientStateClass}").addClass("uploadState-#{uploadStateClass}")
|
||||
|
||||
$clientRetry = $clientState.find('.retry')
|
||||
$uploadRetry = $uploadState.find('.retry')
|
||||
|
||||
if gon.isNativeClient
|
||||
# handle client state
|
||||
|
||||
# only show RETRY button if you have a SQ or if it's missing, and it's been uploaded already
|
||||
if (clientState == @clientStates.sq or clientState == @clientStates.missing) and (uploadState == @uploadStates.me_uploaded or uploadState == @uploadStates.them_uploaded)
|
||||
$clientRetry.show()
|
||||
else
|
||||
$clientRetry.hide()
|
||||
|
||||
# only show RETRY button if you have the HQ track, it's your track, and the server doesn't yet have it
|
||||
if myTrack and @clientStates.hq and (uploadState == @uploadStates.error or uploadState == @uploadStates.me_upload_soon)
|
||||
$uploadRetry.show()
|
||||
else
|
||||
$uploadRetry.hide()
|
||||
else
|
||||
$clientRetry.hide()
|
||||
$uploadRetry.hide()
|
||||
|
||||
associateClientInfo: (recording) =>
|
||||
for clientInfo in recording.local_tracks
|
||||
$track = @list.find(".recorded-track[data-recording-id='#{recording.recording_id}'][data-client-track-id='#{clientInfo.client_track_id}']")
|
||||
|
|
@ -485,7 +510,14 @@ context.JK.SyncViewer = class SyncViewer
|
|||
recordingInfo = null
|
||||
if userSync == 'fake'
|
||||
recordingInfo = arguments[1]
|
||||
userSync = { recording_id: recordingInfo.id, duration: recordingInfo.duration, fake:true }
|
||||
# sift through the recorded_tracks in here; if they are marked discarded, then we can also mark this one discarded too
|
||||
discarded = true
|
||||
for claim in recordingInfo.claimed_recordings
|
||||
if claim.user_id == context.JK.currentUserId
|
||||
discarded = false
|
||||
break
|
||||
|
||||
userSync = { recording_id: recordingInfo.id, duration: recordingInfo.duration, fake:true, discarded: discarded }
|
||||
$mix = $(context._.template(@templateMix.html(), userSync, {variable: 'data'}))
|
||||
else
|
||||
$mix = $(context._.template(@templateMix.html(), userSync, {variable: 'data'}))
|
||||
|
|
@ -504,14 +536,16 @@ context.JK.SyncViewer = class SyncViewer
|
|||
$track.data('sync-viewer', this)
|
||||
$clientState = $track.find('.client-state')
|
||||
$uploadState = $track.find('.upload-state')
|
||||
$clientState.find('.retry').click(this.retryDownloadRecordedTrack)
|
||||
$uploadState.find('.retry').click(this.retryUploadRecordedTrack)
|
||||
$clientStateRetry = $clientState.find('.retry')
|
||||
$clientStateRetry.click(this.retryDownloadRecordedTrack)
|
||||
$uploadStateRetry = $uploadState.find('.retry')
|
||||
$uploadStateRetry.click(this.retryUploadRecordedTrack)
|
||||
context.JK.bindHoverEvents($track)
|
||||
context.JK.bindInstrumentHover($track, {positions:['top'], shrinkToFit: true});
|
||||
context.JK.hoverBubble($clientState, this.onHoverOfStateIndicator, {width:'450px', closeWhenOthersOpen: true, positions:['left']})
|
||||
context.JK.hoverBubble($uploadState, this.onHoverOfStateIndicator, {width:'450px', closeWhenOthersOpen: true, positions:['right']})
|
||||
$clientState.addClass('is-native-client') if context.jamClient.IsNativeClient()
|
||||
$uploadState.addClass('is-native-client') if context.jamClient.IsNativeClient()
|
||||
$clientState.addClass('is-native-client') if gon.isNativeClient
|
||||
$uploadState.addClass('is-native-client') if gon.isNativeClient
|
||||
$track
|
||||
|
||||
createStreamMix: (userSync) =>
|
||||
|
|
@ -523,8 +557,8 @@ context.JK.SyncViewer = class SyncViewer
|
|||
$uploadState.find('.retry').click(this.retryUploadRecordedTrack)
|
||||
context.JK.hoverBubble($clientState, this.onStreamMixHover, {width:'450px', closeWhenOthersOpen: true, positions:['left']})
|
||||
context.JK.hoverBubble($uploadState, this.onStreamMixHover, {width:'450px', closeWhenOthersOpen: true, positions:['right']})
|
||||
$clientState.addClass('is-native-client') if context.jamClient.IsNativeClient()
|
||||
$uploadState.addClass('is-native-client') if context.jamClient.IsNativeClient()
|
||||
$clientState.addClass('is-native-client') if gon.isNativeClient
|
||||
$uploadState.addClass('is-native-client') if gon.isNativeClient
|
||||
$track
|
||||
|
||||
exportRecording: (e) =>
|
||||
|
|
|
|||
|
|
@ -180,6 +180,7 @@ $fair: #cc9900;
|
|||
|
||||
|
||||
@mixin client-state-box {
|
||||
|
||||
.client-state {
|
||||
position:relative;
|
||||
text-align:center;
|
||||
|
|
@ -193,7 +194,6 @@ $fair: #cc9900;
|
|||
|
||||
&.error {
|
||||
background-color: $error;
|
||||
&.is-native-client { .retry { display:inline-block; } }
|
||||
}
|
||||
|
||||
&.hq {
|
||||
|
|
@ -202,12 +202,10 @@ $fair: #cc9900;
|
|||
|
||||
&.sq {
|
||||
background-color: $good;
|
||||
&.is-native-client { .retry { display:inline-block; } }
|
||||
}
|
||||
|
||||
&.missing {
|
||||
background-color: $error;
|
||||
&.is-native-client { .retry { display:inline-block; } }
|
||||
}
|
||||
|
||||
&.discarded {
|
||||
|
|
@ -240,7 +238,6 @@ $fair: #cc9900;
|
|||
|
||||
&.error {
|
||||
background-color: $error;
|
||||
&.is-native-client { .retry { display:inline-block; } }
|
||||
}
|
||||
|
||||
&.missing {
|
||||
|
|
@ -249,7 +246,6 @@ $fair: #cc9900;
|
|||
|
||||
&.upload-soon {
|
||||
background-color: $fair;
|
||||
&.is-native-client { .retry { display:inline-block; } }
|
||||
}
|
||||
|
||||
&.uploaded {
|
||||
|
|
@ -278,7 +274,7 @@ $fair: #cc9900;
|
|||
color:white;
|
||||
|
||||
&.still-uploading { background-color: $fair; }
|
||||
&.discard {background-color: $unknown; }
|
||||
&.discarded {background-color: $unknown; }
|
||||
&.unknown { background-color: $unknown; }
|
||||
&.error { background-color: $error; }
|
||||
&.mixed { background-color: $good; }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
class ApiRecordingsController < ApiController
|
||||
|
||||
before_filter :api_signed_in_user, :except => [ :add_like ]
|
||||
|
||||
before_filter :lookup_recording, :only => [ :show, :stop, :claim, :discard, :keep ]
|
||||
before_filter :lookup_recorded_track, :only => [ :download, :upload_next_part, :upload_sign, :upload_part_complete, :upload_complete ]
|
||||
before_filter :lookup_recorded_video, :only => [ :video_upload_sign, :video_upload_start, :video_upload_complete ]
|
||||
|
|
@ -239,6 +240,61 @@ class ApiRecordingsController < ApiController
|
|||
end
|
||||
|
||||
|
||||
def upload_next_part_stream_mix
|
||||
length = params[:length]
|
||||
md5 = params[:md5]
|
||||
|
||||
@quick_mix.upload_next_part(length, md5)
|
||||
|
||||
if @quick_mix.errors.any?
|
||||
|
||||
response.status = :unprocessable_entity
|
||||
# this is not typical, but please don't change this line unless you are sure it won't break anything
|
||||
# this is needed because after_rollback in the RecordedTrackObserver touches the model and something about it's
|
||||
# state doesn't cause errors to shoot out like normal.
|
||||
render :json => { :errors => @quick_mix.errors }, :status => 422
|
||||
else
|
||||
result = {
|
||||
:part => @quick_mix.next_part_to_upload,
|
||||
:offset => @quick_mix.file_offset.to_s
|
||||
}
|
||||
|
||||
render :json => result, :status => 200
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def upload_sign_stream_mix
|
||||
render :json => @quick_mix.upload_sign(params[:md5]), :status => 200
|
||||
end
|
||||
|
||||
def upload_part_complete_stream_mix
|
||||
part = params[:part]
|
||||
offset = params[:offset]
|
||||
|
||||
@quick_mix.upload_part_complete(part, offset)
|
||||
|
||||
if @quick_mix.errors.any?
|
||||
response.status = :unprocessable_entity
|
||||
respond_with @quick_mix
|
||||
else
|
||||
render :json => {}, :status => 200
|
||||
end
|
||||
end
|
||||
|
||||
def upload_complete_stream_mix
|
||||
@quick_mix.upload_complete
|
||||
|
||||
if @quick_mix.errors.any?
|
||||
response.status = :unprocessable_entity
|
||||
respond_with @quick_mix
|
||||
return
|
||||
else
|
||||
render :json => {}, :status => 200
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def upload_next_part_stream_mix
|
||||
length = params[:length]
|
||||
md5 = params[:md5]
|
||||
|
|
@ -305,14 +361,14 @@ class ApiRecordingsController < ApiController
|
|||
raise PermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR unless @recorded_track.recording.has_access?(current_user)
|
||||
end
|
||||
|
||||
def lookup_recorded_video
|
||||
@recorded_video = RecordedVideo.find_by_recording_id_and_client_video_source_id!(params[:id], params[:video_id])
|
||||
raise PermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR unless @recorded_video.recording.has_access?(current_user)
|
||||
end
|
||||
|
||||
def lookup_stream_mix
|
||||
@quick_mix = QuickMix.find_by_recording_id_and_user_id!(params[:id], current_user.id)
|
||||
raise PermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR unless @quick_mix.recording.has_access?(current_user)
|
||||
end
|
||||
|
||||
def lookup_recorded_video
|
||||
@recorded_video = RecordedVideo.find_by_recording_id_and_client_video_source_id!(params[:id], params[:video_id])
|
||||
raise PermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR unless @recorded_video.recording.has_access?(current_user)
|
||||
end
|
||||
|
||||
end # class
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
<% end %>
|
||||
|
||||
<div class="recordings-page">
|
||||
<% if @claimed_recording.is_public %>
|
||||
<% if @claimed_recording.is_public || @claimed_recording.recording.has_access?(current_user) %>
|
||||
<div class="landing-band">
|
||||
<% unless @claimed_recording.recording.band.blank? %>
|
||||
<div class="landing-avatar">
|
||||
|
|
@ -97,7 +97,7 @@
|
|||
<% end %>
|
||||
</div>
|
||||
|
||||
<% if @claimed_recording.is_public %>
|
||||
<% if @claimed_recording.is_public || @claimed_recording.recording.has_access?(current_user) %>
|
||||
<% if signed_in? %>
|
||||
<% unless @claimed_recording.recording.band.nil? %>
|
||||
<%= render :partial => "shared/landing_sidebar", :locals => {:user => @claimed_recording.recording.band, :recent_history => @claimed_recording.recording.band.recent_history} %>
|
||||
|
|
|
|||
|
|
@ -179,6 +179,8 @@ if defined?(Bundler)
|
|||
|
||||
config.audiomixer_path = "/var/lib/audiomixer/audiomixer/audiomixerapp"
|
||||
config.ffmpeg_path = ENV['FFMPEG_PATH'] || (File.exist?('/usr/local/bin/ffmpeg') ? '/usr/local/bin/ffmpeg' : '/usr/bin/ffmpeg')
|
||||
config.normalize_ogg_path = ENV['NORMALIZE_OGG_PATH'] || (File.exist?('/usr/local/bin/normalize-ogg') ? '/usr/local/bin/normalize-ogg' : '/usr/bin/normalize-ogg')
|
||||
config.normalize_mp3_path = ENV['NORMALIZE_MP3_PATH'] || (File.exist?('/usr/local/bin/normalize-mp3') ? '/usr/local/bin/normalize-mp3' : '/usr/bin/normalize-mp3')
|
||||
|
||||
# if it looks like linux, use init.d script; otherwise use kill
|
||||
config.icecast_reload_cmd = ENV['ICECAST_RELOAD_CMD'] || (File.exist?('/usr/local/bin/icecast2') ? "bash -l -c #{Shellwords.escape("sudo /etc/init.d/icecast2 reload")}" : "bash -l -c #{Shellwords.escape("kill -1 `ps -f | grep /usr/local/bin/icecast | grep -v grep | awk \'{print $2}\'`")}")
|
||||
|
|
|
|||
|
|
@ -401,8 +401,8 @@ SampleApp::Application.routes.draw do
|
|||
match '/recordings/:id/comments' => 'api_recordings#add_comment', :via => :post, :as => 'api_recordings_add_comment'
|
||||
match '/recordings/:id/likes' => 'api_recordings#add_like', :via => :post, :as => 'api_recordings_add_like'
|
||||
match '/recordings/:id/discard' => 'api_recordings#discard', :via => :post, :as => 'api_recordings_discard'
|
||||
|
||||
# Recordings - recorded_tracks
|
||||
|
||||
match '/recordings/:id/tracks/:track_id' => 'api_recordings#show_recorded_track', :via => :get, :as => 'api_recordings_show_recorded_track'
|
||||
match '/recordings/:id/tracks/:track_id/download' => 'api_recordings#download', :via => :get, :as => 'api_recordings_download'
|
||||
match '/recordings/:id/tracks/:track_id/upload_next_part' => 'api_recordings#upload_next_part', :via => :get
|
||||
|
|
|
|||
|
|
@ -11,6 +11,26 @@ describe "Music Session", :js => true, :type => :feature, :capybara_feature => t
|
|||
|
||||
subject { page }
|
||||
|
||||
describe "recorded session" do
|
||||
|
||||
before(:each) do
|
||||
ActiveMusicSession.delete_all
|
||||
MusicSession.delete_all
|
||||
end
|
||||
|
||||
let(:searcher) { FactoryGirl.create(:user) }
|
||||
let(:creator) { FactoryGirl.create(:user) }
|
||||
let(:conn) { FactoryGirl.create(:connection, :user => creator) }
|
||||
let(:description) {'hot recordings in here'}
|
||||
let(:session) {FactoryGirl.create(:active_music_session, creator:creator, description: description)}
|
||||
let(:recording) {FactoryGirl.create(:recording, music_session: session, owner: creator)}
|
||||
|
||||
it "won't let user join" do
|
||||
recording.touch
|
||||
join_session(searcher, description:'hot recordings in here', no_verify:true)
|
||||
find('#notification p').text('The session is currently recording.')
|
||||
end
|
||||
end
|
||||
|
||||
context "last person" do
|
||||
before(:each) do
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe "Landing", :js => true, :type => :feature, :capybara_feature => true do
|
||||
describe "Landing" do
|
||||
|
||||
let (:user) { FactoryGirl.create(:user) }
|
||||
|
||||
|
|
@ -10,41 +10,70 @@ describe "Landing", :js => true, :type => :feature, :capybara_feature => true do
|
|||
Recording.delete_all
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
MusicSession.delete_all
|
||||
sign_in_poltergeist(user)
|
||||
end
|
||||
|
||||
let (:claimed_recording) { FactoryGirl.create(:claimed_recording) }
|
||||
let (:recording) { claimed_recording.recording }
|
||||
|
||||
it "should render comments" do
|
||||
describe "no js required" do
|
||||
|
||||
recording = ClaimedRecording.first
|
||||
comment = "test comment"
|
||||
timestamp = "less than a minute ago"
|
||||
url = "/recordings/#{claimed_recording.id}"
|
||||
visit url
|
||||
it "shows private recording to someone who was in the session" do
|
||||
# make the session hidden
|
||||
claimed_recording.is_public = false
|
||||
claimed_recording.save!
|
||||
|
||||
fill_in "txtRecordingComment", with: comment
|
||||
find('#btnPostComment').trigger(:click)
|
||||
visit "/recordings/#{claimed_recording.id}"
|
||||
|
||||
# (1) Test a user creating a comment and ensure it displays.
|
||||
# and verify that after we visit the page, we can see the name of it
|
||||
find('strong', text: 'RECORDING NOT FOUND')
|
||||
|
||||
# comment body
|
||||
find('div.comment-text', text: comment)
|
||||
# log in the user who was a part of the session
|
||||
sign_in(claimed_recording.user)
|
||||
|
||||
# timestamp
|
||||
find('div.comment-timestamp', text: timestamp)
|
||||
visit "/recordings/#{claimed_recording.id}"
|
||||
|
||||
# (2) Test a user visiting a landing page with an existing comment.
|
||||
# and verify that after we visit the page, we can see the name of it
|
||||
find('h2', text: claimed_recording.name)
|
||||
end
|
||||
end
|
||||
|
||||
# re-visit page to reload from database
|
||||
visit url
|
||||
|
||||
# comment body
|
||||
find('div.comment-text', text: comment)
|
||||
describe "js required", :js => true, :type => :feature, :capybara_feature => true do
|
||||
|
||||
# timestamp
|
||||
find('div.comment-timestamp', text: timestamp)
|
||||
before(:each) do
|
||||
MusicSession.delete_all
|
||||
sign_in_poltergeist(user)
|
||||
end
|
||||
|
||||
|
||||
it "should render comments" do
|
||||
|
||||
recording = ClaimedRecording.first
|
||||
comment = "test comment"
|
||||
timestamp = "less than a minute ago"
|
||||
url = "/recordings/#{claimed_recording.id}"
|
||||
visit url
|
||||
|
||||
fill_in "txtRecordingComment", with: comment
|
||||
find('#btnPostComment').trigger(:click)
|
||||
|
||||
# (1) Test a user creating a comment and ensure it displays.
|
||||
|
||||
# comment body
|
||||
find('div.comment-text', text: comment)
|
||||
|
||||
# timestamp
|
||||
find('div.comment-timestamp', text: timestamp)
|
||||
|
||||
# (2) Test a user visiting a landing page with an existing comment.
|
||||
|
||||
# re-visit page to reload from database
|
||||
visit url
|
||||
|
||||
# comment body
|
||||
find('div.comment-text', text: comment)
|
||||
|
||||
# timestamp
|
||||
find('div.comment-timestamp', text: timestamp)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -457,9 +457,11 @@ def join_session(joiner, options)
|
|||
# verify the session description is seen by second client
|
||||
expect(page).to have_text(description)
|
||||
find('.join-link').trigger(:click)
|
||||
find('#btn-accept-terms').trigger(:click)
|
||||
expect(page).to have_selector('h2', text: 'my tracks')
|
||||
find('#session-screen .session-mytracks .session-track')
|
||||
unless options[:no_verify]
|
||||
find('#btn-accept-terms').trigger(:click)
|
||||
expect(page).to have_selector('h2', text: 'my tracks')
|
||||
find('#session-screen .session-mytracks .session-track')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ module JamWebsockets
|
|||
@router.periodical_check_connections
|
||||
|
||||
EventMachine::PeriodicTimer.new(2) do
|
||||
sane_logging { @router.periodical_check_connections }
|
||||
safety_net { sane_logging { @router.periodical_check_connections } }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ module JamWebsockets
|
|||
@router.periodical_check_clients
|
||||
|
||||
EventMachine::PeriodicTimer.new(30) do
|
||||
sane_logging { @router.periodical_check_clients }
|
||||
safety_net { sane_logging { @router.periodical_check_clients } }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -98,16 +98,29 @@ module JamWebsockets
|
|||
@router.periodical_flag_connections
|
||||
|
||||
EventMachine::PeriodicTimer.new(2) do
|
||||
sane_logging { @router.periodical_flag_connections }
|
||||
safety_net { sane_logging { @router.periodical_flag_connections } }
|
||||
end
|
||||
end
|
||||
|
||||
def start_stats_dump
|
||||
EventMachine::PeriodicTimer.new(60) do
|
||||
@router.periodical_stats_dump
|
||||
safety_net { @router.periodical_stats_dump }
|
||||
end
|
||||
end
|
||||
|
||||
# this was added for this reason: https://jamkazam.atlassian.net/browse/VRFS-2425
|
||||
# if an unhandled exception occurs in PeriodicTimer, it just kills all future timers; doesn't kill the app.
|
||||
# not really what you want.
|
||||
|
||||
# so, we signal to Bugsnag, so we know really bad stuff is happening, but we also move
|
||||
def safety_net(&blk)
|
||||
begin
|
||||
blk.call
|
||||
rescue => e
|
||||
Bugsnag.notify(e)
|
||||
@log.error("unhandled exception in EM Timer #{e}")
|
||||
end
|
||||
end
|
||||
def sane_logging(&blk)
|
||||
# used around repeated transactions that cause too much ActiveRecord::Base logging
|
||||
# example is handling heartbeats
|
||||
|
|
|
|||
Loading…
Reference in New Issue