Merge branch 'develop' into feature/rsvp_slot_conflict
This commit is contained in:
commit
300bc2cd82
|
|
@ -224,3 +224,4 @@ emails_from_update2.sql
|
|||
add_youtube_flag_to_claimed_recordings.sql
|
||||
add_session_create_type.sql
|
||||
user_syncs_and_quick_mix.sql
|
||||
user_syncs_fix_dup_tracks_2408.sql
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
DROP VIEW user_syncs;
|
||||
|
||||
CREATE VIEW user_syncs AS
|
||||
SELECT DISTINCT b.id AS recorded_track_id,
|
||||
CAST(NULL as BIGINT) AS mix_id,
|
||||
CAST(NULL as BIGINT) as quick_mix_id,
|
||||
b.id AS unified_id,
|
||||
a.user_id AS user_id,
|
||||
b.fully_uploaded,
|
||||
recordings.created_at AS created_at,
|
||||
recordings.id AS recording_id
|
||||
FROM recorded_tracks a INNER JOIN recordings ON a.recording_id = recordings.id AND duration IS NOT NULL AND all_discarded = FALSE INNER JOIN recorded_tracks b ON a.recording_id = b.recording_id
|
||||
UNION ALL
|
||||
SELECT CAST(NULL as BIGINT) AS recorded_track_id,
|
||||
mixes.id AS mix_id,
|
||||
CAST(NULL as BIGINT) AS quick_mix_id,
|
||||
mixes.id AS unified_id,
|
||||
claimed_recordings.user_id AS user_id,
|
||||
NULL as fully_uploaded,
|
||||
recordings.created_at AS created_at,
|
||||
recordings.id AS recording_id
|
||||
FROM mixes INNER JOIN recordings ON mixes.recording_id = recordings.id INNER JOIN claimed_recordings ON recordings.id = claimed_recordings.recording_id WHERE claimed_recordings.discarded = FALSE
|
||||
UNION ALL
|
||||
SELECT CAST(NULL as BIGINT) AS recorded_track_id,
|
||||
CAST(NULL as BIGINT) AS mix_id,
|
||||
quick_mixes.id AS quick_mix_id,
|
||||
quick_mixes.id AS unified_id,
|
||||
quick_mixes.user_id,
|
||||
quick_mixes.fully_uploaded,
|
||||
recordings.created_at AS created_at,
|
||||
recordings.id AS recording_id
|
||||
FROM quick_mixes INNER JOIN recordings ON quick_mixes.recording_id = recordings.id AND duration IS NOT NULL AND all_discarded = FALSE;
|
||||
|
|
@ -206,6 +206,18 @@ module JamRuby
|
|||
|
||||
end
|
||||
|
||||
def cleanup_files()
|
||||
File.delete(@output_ogg_filename) if File.exists(@output_ogg_filename)
|
||||
File.delete(@output_mp3_filename) if File.exists(@output_mp3_filename)
|
||||
File.delete(@manifest_file) if File.exists(@manifest_file)
|
||||
File.delete(@error_out_filename) if File.exists(@error_out_filename)
|
||||
|
||||
@manifest[:files].each do |file|
|
||||
filename = file[:filename]
|
||||
File.delete(filename) if File.exists(filename)
|
||||
end
|
||||
end
|
||||
|
||||
def post_success(mix)
|
||||
|
||||
ogg_length = File.size(@output_ogg_filename)
|
||||
|
|
@ -220,6 +232,7 @@ module JamRuby
|
|||
mix.finish(ogg_length, ogg_md5.to_s, mp3_length, mp3_md5.to_s)
|
||||
end
|
||||
|
||||
|
||||
def post_error(mix, e)
|
||||
begin
|
||||
|
||||
|
|
@ -265,6 +278,9 @@ module JamRuby
|
|||
|
||||
post_success(mix)
|
||||
|
||||
# only cleanup files if we manage to get this far
|
||||
cleanup_files
|
||||
|
||||
@@log.info("audiomixer job successful. mix_id #{mix_id}")
|
||||
|
||||
rescue Exception => e
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ module JamRuby
|
|||
|
||||
post_success(@quick_mix)
|
||||
|
||||
cleanup_files
|
||||
|
||||
@@log.info("audiomixer job successful. mix_id #{quick_mix_id}")
|
||||
|
||||
rescue Exception => e
|
||||
|
|
@ -121,6 +123,11 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
def cleanup_files()
|
||||
File.delete(@input_ogg_filename) if File.exists(@input_ogg_filename)
|
||||
File.delete(@output_mp3_filename) if File.exists(@output_mp3_filename)
|
||||
end
|
||||
|
||||
|
||||
def fetch_audio_files
|
||||
@input_ogg_filename = Dir::Tmpname.make_tmpname( ["#{Dir.tmpdir}/quick_mixer_#{@quick_mix.id}}", '.ogg'], nil)
|
||||
|
|
|
|||
|
|
@ -167,6 +167,54 @@ describe UserSync do
|
|||
user_syncs.length.should == 0
|
||||
end
|
||||
end
|
||||
|
||||
describe "one recording with multi-track users" do
|
||||
let!(:recording1) {
|
||||
recording = FactoryGirl.create(:recording, owner: user1, band: nil, duration:1)
|
||||
recording.recorded_tracks << FactoryGirl.create(:recorded_track, recording: recording, user: recording.owner)
|
||||
recording.recorded_tracks << FactoryGirl.create(:recorded_track, recording: recording, user: recording.owner)
|
||||
recording.recorded_tracks << FactoryGirl.create(:recorded_track, recording: recording, user: user2)
|
||||
recording.recorded_tracks << FactoryGirl.create(:recorded_track, recording: recording, user: user2)
|
||||
recording.save!
|
||||
recording.reload
|
||||
recording
|
||||
}
|
||||
|
||||
let(:sorted_tracks) {
|
||||
Array.new(recording1.recorded_tracks).sort! {|a, b|
|
||||
if a.created_at == b.created_at
|
||||
a.id <=> b.id
|
||||
else
|
||||
a.created_at <=> b.created_at
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
it "one user decides to keep the recording" do
|
||||
claimed_recording = FactoryGirl.create(:claimed_recording, user: user1, recording: recording1, discarded:false)
|
||||
claimed_recording.recording.should == recording1
|
||||
|
||||
data = UserSync.index({user_id: user1.id})
|
||||
data[:next].should be_nil
|
||||
user_syncs = data[:query]
|
||||
user_syncs.length.should == 4
|
||||
user_syncs[0].recorded_track.should == sorted_tracks[0]
|
||||
user_syncs[1].recorded_track.should == sorted_tracks[1]
|
||||
user_syncs[2].recorded_track.should == sorted_tracks[2]
|
||||
user_syncs[3].recorded_track.should == sorted_tracks[3]
|
||||
|
||||
data = UserSync.index({user_id: user2.id})
|
||||
data[:next].should be_nil
|
||||
user_syncs = data[:query]
|
||||
user_syncs.length.should == 4
|
||||
user_syncs[0].recorded_track.should == sorted_tracks[0]
|
||||
user_syncs[1].recorded_track.should == sorted_tracks[1]
|
||||
user_syncs[2].recorded_track.should == sorted_tracks[2]
|
||||
user_syncs[3].recorded_track.should == sorted_tracks[3]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "pagination" do
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class RecordingUtils
|
|||
mixStateDefinition: (mixState) =>
|
||||
|
||||
definition = switch mixState
|
||||
when 'still-uploading' then "STILL UPLOADING means the you or others in the recording have not uploaded enough information yet to make a mix."
|
||||
when 'still-uploading' then "STILL UPLOADING means you or others in the recording have not uploaded enough information yet to make a mix."
|
||||
when 'stream-mix' then "STREAM MIX means a user's real-time mix is available to listen to."
|
||||
when 'discarded' then "DISCARDED means you chose to not keep this recording when the recording was over."
|
||||
when 'mixed' then "MIXED means all tracks have been uploaded, and a final mix has been made."
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
var sessionPageEnterDeferred = null;
|
||||
var sessionPageEnterTimeout = null;
|
||||
var startTime = null;
|
||||
var joinDeferred = null;
|
||||
|
||||
server.registerOnSocketClosed(onWebsocketDisconnected);
|
||||
|
||||
|
|
@ -123,10 +124,18 @@
|
|||
*/
|
||||
function joinSession(sessionId) {
|
||||
logger.debug("SessionModel.joinSession(" + sessionId + ")");
|
||||
var deferred = joinSessionRest(sessionId);
|
||||
joinDeferred = joinSessionRest(sessionId);
|
||||
|
||||
joinDeferred
|
||||
.done(function(response){
|
||||
|
||||
if(!inSession()) {
|
||||
// the user has left the session before they got joined. We need to issue a leave again to the server to make sure they are out
|
||||
logger.debug("user left before fully joined to session. telling server again that they have left")
|
||||
leaveSessionRest(response.id);
|
||||
return;
|
||||
}
|
||||
|
||||
deferred
|
||||
.done(function(response){
|
||||
logger.debug("calling jamClient.JoinSession");
|
||||
// on temporary disconnect scenarios, a user may already be in a session when they enter this path
|
||||
// so we avoid double counting
|
||||
|
|
@ -153,7 +162,7 @@
|
|||
updateCurrentSession(null);
|
||||
});
|
||||
|
||||
return deferred;
|
||||
return joinDeferred;
|
||||
}
|
||||
|
||||
function performLeaveSession(deferred) {
|
||||
|
|
@ -251,13 +260,15 @@
|
|||
}
|
||||
|
||||
// universal place to clean up, reset items
|
||||
function sessionEnded() {
|
||||
// fullyJoined means the user stayed in the screen until they had a successful rest.joinSession
|
||||
// you might not get a fully joined if you join/leave really quickly before the REST API completes
|
||||
function sessionEnded(fullyJoined) {
|
||||
//cleanup
|
||||
|
||||
server.unregisterMessageCallback(context.JK.MessageType.SESSION_JOIN, trackChanges);
|
||||
server.unregisterMessageCallback(context.JK.MessageType.SESSION_DEPART, trackChanges);
|
||||
server.unregisterMessageCallback(context.JK.MessageType.TRACKS_CHANGED, trackChanges);
|
||||
server.registerMessageCallback(context.JK.MessageType.HEARTBEAT_ACK, trackChanges);
|
||||
server.unregisterMessageCallback(context.JK.MessageType.HEARTBEAT_ACK, trackChanges);
|
||||
|
||||
if(sessionPageEnterDeferred != null) {
|
||||
sessionPageEnterDeferred.reject('session_over');
|
||||
|
|
@ -265,7 +276,10 @@
|
|||
}
|
||||
userTracks = null;
|
||||
startTime = null;
|
||||
$(document).trigger(EVENTS.SESSION_ENDED, {session: {id: currentSessionId}});
|
||||
joinDeferred = null;
|
||||
if(fullyJoined) {
|
||||
$(document).trigger(EVENTS.SESSION_ENDED, {session: {id: currentSessionId}});
|
||||
}
|
||||
currentSessionId = null;
|
||||
}
|
||||
|
||||
|
|
@ -280,8 +294,8 @@
|
|||
currentSession = sessionData;
|
||||
|
||||
// the 'beforeUpdate != null' makes sure we only do a clean up one time internally
|
||||
if(sessionData == null && beforeUpdate != null) {
|
||||
sessionEnded();
|
||||
if(sessionData == null) {
|
||||
sessionEnded(beforeUpdate != null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -538,51 +552,65 @@
|
|||
|
||||
if(inSession() && text == "RebuildAudioIoControl") {
|
||||
|
||||
if(sessionPageEnterDeferred) {
|
||||
// this means we are still waiting for the BACKEND_MIXER_CHANGE that indicates we have user tracks built-out/ready
|
||||
|
||||
// we will get at least one BACKEND_MIXER_CHANGE that corresponds to the backend doing a 'audio pause', which won't matter much
|
||||
// so we need to check that we actaully have userTracks before considering ourselves done
|
||||
var inputTracks = context.JK.TrackHelpers.getUserTracks(context.jamClient);
|
||||
if(inputTracks.length > 0) {
|
||||
logger.debug("obtained tracks at start of session")
|
||||
sessionPageEnterDeferred.resolve(inputTracks);
|
||||
sessionPageEnterDeferred = null;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// the backend will send these events rapid-fire back to back.
|
||||
// the server can still perform correctly, but it is nicer to wait 100 ms to let them all fall through
|
||||
if(backendMixerAlertThrottleTimer) {clearTimeout(backendMixerAlertThrottleTimer);}
|
||||
|
||||
backendMixerAlertThrottleTimer = setTimeout(function() {
|
||||
// this is a local change to our tracks. we need to tell the server about our updated track information
|
||||
var inputTracks = context.JK.TrackHelpers.getUserTracks(context.jamClient);
|
||||
|
||||
// create a trackSync request based on backend data
|
||||
var syncTrackRequest = {};
|
||||
syncTrackRequest.client_id = app.clientId;
|
||||
syncTrackRequest.tracks = inputTracks;
|
||||
syncTrackRequest.id = id();
|
||||
if(sessionPageEnterDeferred) {
|
||||
// this means we are still waiting for the BACKEND_MIXER_CHANGE that indicates we have user tracks built-out/ready
|
||||
|
||||
rest.putTrackSyncChange(syncTrackRequest)
|
||||
.done(function() {
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
if(jqXHR.status != 404) {
|
||||
app.notify({
|
||||
"title": "Can't Sync Local Tracks",
|
||||
"text": "The client is unable to sync local track information with the server. You should rejoin the session to ensure a good experience.",
|
||||
"icon_url": "/assets/content/icon_alert_big.png"
|
||||
});
|
||||
}
|
||||
else {
|
||||
logger.debug("Unable to sync local tracks because session is gone.")
|
||||
// we will get at least one BACKEND_MIXER_CHANGE that corresponds to the backend doing a 'audio pause', which won't matter much
|
||||
// so we need to check that we actaully have userTracks before considering ourselves done
|
||||
var inputTracks = context.JK.TrackHelpers.getUserTracks(context.jamClient);
|
||||
if(inputTracks.length > 0) {
|
||||
logger.debug("obtained tracks at start of session")
|
||||
sessionPageEnterDeferred.resolve(inputTracks);
|
||||
sessionPageEnterDeferred = null;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// wait until we are fully in session before trying to sync tracks to server
|
||||
if(joinDeferred) {
|
||||
joinDeferred.done(function() {
|
||||
|
||||
// double check that we are in session, since a bunch could have happened since then
|
||||
if(!inSession()) {
|
||||
logger.debug("dropping queued up sync tracks because no longer in session");
|
||||
return;
|
||||
}
|
||||
|
||||
// this is a local change to our tracks. we need to tell the server about our updated track information
|
||||
var inputTracks = context.JK.TrackHelpers.getUserTracks(context.jamClient);
|
||||
|
||||
// create a trackSync request based on backend data
|
||||
var syncTrackRequest = {};
|
||||
syncTrackRequest.client_id = app.clientId;
|
||||
syncTrackRequest.tracks = inputTracks;
|
||||
syncTrackRequest.id = id();
|
||||
|
||||
rest.putTrackSyncChange(syncTrackRequest)
|
||||
.done(function() {
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
if(jqXHR.status != 404) {
|
||||
app.notify({
|
||||
"title": "Can't Sync Local Tracks",
|
||||
"text": "The client is unable to sync local track information with the server. You should rejoin the session to ensure a good experience.",
|
||||
"icon_url": "/assets/content/icon_alert_big.png"
|
||||
});
|
||||
}
|
||||
else {
|
||||
logger.debug("Unable to sync local tracks because session is gone.")
|
||||
}
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
}, 100);
|
||||
}
|
||||
else if(inSession() && (text == 'RebuildMediaControl' || text == 'RebuildRemoteUserControl')) {
|
||||
|
|
|
|||
|
|
@ -401,7 +401,7 @@ context.JK.SyncViewer = class SyncViewer
|
|||
summary = "Both you and the JamKazam server have the high-quality version of this track. Once all the other tracks for this recording are also synchronized, then the final mix can be made."
|
||||
|
||||
clientStateDefinition = switch clientState
|
||||
when @clientStates.too_many_downloads then "This track has been downloaded a unusually large number of times. No more downloads are allowed."
|
||||
when @clientStates.too_many_downloads then "This track has been downloaded an unusually large number of times. No more downloads are allowed."
|
||||
when @clientStates.hq then "HIGHEST QUALITY means you have the original version of this track, as recorded by the user that made it."
|
||||
when @clientStates.sq then "STREAM QUALITY means you have the version of the track that you received over the internet in real-time."
|
||||
when @clientStates.missing then "MISSING means you do not have this track anymore."
|
||||
|
|
@ -529,6 +529,10 @@ context.JK.SyncViewer = class SyncViewer
|
|||
|
||||
exportRecording: (e) =>
|
||||
$export = $(e.target)
|
||||
if context.JK.CurrentSessionModel and context.JK.CurrentSessionModel.inSession()
|
||||
context.JK.confirmBubble($export, 'sync-viewer-paused', {}, {offsetParent: $export.closest('.dialog')})
|
||||
return
|
||||
|
||||
recordingId = $export.closest('.details').attr('data-recording-id')
|
||||
if !recordingId? or recordingId == ""
|
||||
throw "exportRecording can't find data-recording-id"
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@
|
|||
|
||||
<script type="text/template" id="template-help-sync-viewer-paused">
|
||||
<div class="help-sync-viewer-paused">
|
||||
JamKazam prevents file uploads and downloads while in a session.
|
||||
JamKazam prevents file uploads, downloads, and recording exports while in a session.
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue