* VRFS-946 and VRFS-922 - in-session recording features complete
This commit is contained in:
parent
17486c6ed2
commit
fa23c267f5
|
|
@ -83,3 +83,4 @@ bands_geocoding.sql
|
|||
store_s3_filenames.sql
|
||||
discardable_recorded_tracks.sql
|
||||
music_sessions_have_claimed_recording.sql
|
||||
discardable_recorded_tracks2.sql
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE recorded_tracks ALTER COLUMN discard DROP DEFAULT;
|
||||
ALTER TABLE recorded_tracks ALTER COLUMN discard DROP NOT NULL;
|
||||
|
|
@ -49,6 +49,7 @@ module ValidationMessages
|
|||
ALREADY_PLAYBACK_RECORDING = "already playing a recording"
|
||||
NO_LONGER_RECORDING = "no longer recording"
|
||||
NOT_IN_SESSION = "not in session"
|
||||
PREVIOUS_RECORDING_STILL_BEING_FINALIZED = "still has previous recording being finalized"
|
||||
|
||||
# recorded tracks
|
||||
ALREADY_UPLOADED = "already set"
|
||||
|
|
|
|||
|
|
@ -179,6 +179,10 @@ module JamRuby
|
|||
return self.users.exists? user
|
||||
end
|
||||
|
||||
def most_recent_recording
|
||||
recordings.where(:music_session_id => self.id).order('created_at desc').limit(1).first
|
||||
end
|
||||
|
||||
# is this music session currently recording?
|
||||
def is_recording?
|
||||
recordings.where(:duration => nil).count > 0
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ module JamRuby
|
|||
has_many :recorded_tracks, :class_name => "JamRuby::RecordedTrack", :foreign_key => :recording_id
|
||||
validates :music_session, :presence => true
|
||||
validate :not_already_recording, :on => :create
|
||||
validate :not_still_finalizing_previous, :on => :create
|
||||
validate :not_playback_recording, :on => :create
|
||||
validate :already_stopped_recording
|
||||
|
||||
|
|
@ -23,6 +24,28 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
def not_still_finalizing_previous
|
||||
# after a recording is done, users need to keep or discard it.
|
||||
# this checks if the previous recording is still being finalized
|
||||
|
||||
unless music_session.is_recording?
|
||||
previous_recording = music_session.most_recent_recording
|
||||
if previous_recording
|
||||
previous_recording.recorded_tracks.each do |recorded_track|
|
||||
# if at least one user hasn't taken any action yet...
|
||||
if recorded_track.discard.nil?
|
||||
# and they are still around and in this music session still...
|
||||
connection = Connection.find_by_client_id(recorded_track.client_id)
|
||||
if !connection.nil? && connection.music_session == music_session
|
||||
errors.add(:music_session, ValidationMessages::PREVIOUS_RECORDING_STILL_BEING_FINALIZED)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def not_playback_recording
|
||||
if music_session.is_playing_recording?
|
||||
errors.add(:music_session, ValidationMessages::ALREADY_PLAYBACK_RECORDING)
|
||||
|
|
@ -39,7 +62,7 @@ module JamRuby
|
|||
unless self.users.exists?(user)
|
||||
raise PermissionError, "user was not in this session"
|
||||
end
|
||||
RecordedTrack.where(:recording_id=> self.id).where(:user_id=> user.id)
|
||||
recorded_tracks.where(:user_id=> user.id)
|
||||
end
|
||||
|
||||
def has_access?(user)
|
||||
|
|
@ -91,12 +114,13 @@ module JamRuby
|
|||
self
|
||||
end
|
||||
|
||||
|
||||
# Called when a user wants to "claim" a recording. To do this, the user must have been one of the tracks in the recording.
|
||||
def claim(user, name, description, genre, is_public, is_downloadable)
|
||||
|
||||
unless self.users.exists?(user)
|
||||
raise PermissionError, "user was not in this session"
|
||||
end
|
||||
end
|
||||
|
||||
claimed_recording = ClaimedRecording.new
|
||||
claimed_recording.user = user
|
||||
|
|
@ -108,8 +132,17 @@ module JamRuby
|
|||
claimed_recording.is_downloadable = is_downloadable
|
||||
self.claimed_recordings << claimed_recording
|
||||
|
||||
if claimed_recording.save
|
||||
discard(user)
|
||||
end
|
||||
|
||||
claimed_recording
|
||||
end
|
||||
|
||||
# the user votes to discard their tracks for this recording
|
||||
def discard(user)
|
||||
recorded_tracks_for_user(user).update_all(:discard => true)
|
||||
end
|
||||
|
||||
# Find out if all the tracks for this recording have been uploaded
|
||||
def uploaded?
|
||||
|
|
@ -119,11 +152,6 @@ module JamRuby
|
|||
return true
|
||||
end
|
||||
|
||||
# Discards this recording and schedules deletion of all files associated with it.
|
||||
def discard
|
||||
self.destroy
|
||||
end
|
||||
|
||||
def self.list_downloads(user, limit = 100, since = 0)
|
||||
since = 0 unless since || since == '' # guard against nil
|
||||
downloads = []
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
require 'spec_helper'
|
||||
|
||||
def valid_claimed_recording
|
||||
@claimed_recording.name = "hello"
|
||||
@claimed_recording.description = "description"
|
||||
@claimed_recording.genre = Genre.first
|
||||
@claimed_recording.is_public = true
|
||||
@claimed_recording.is_downloadable = true
|
||||
@claimed_recording
|
||||
@name = "hello"
|
||||
@description = "description"
|
||||
@genre = Genre.first
|
||||
@is_public = true
|
||||
@is_downloadable = true
|
||||
end
|
||||
|
||||
def make_claim
|
||||
@claimed_recording = @recording.claim(@user, @name, @description, @genre, @is_public, @is_downloadable)
|
||||
end
|
||||
|
||||
describe ClaimedRecording do
|
||||
|
|
@ -22,33 +25,37 @@ describe ClaimedRecording do
|
|||
@recording = Recording.start(@music_session, @user)
|
||||
@recording.stop
|
||||
@recording.reload
|
||||
@genre = FactoryGirl.create(:genre)
|
||||
@recording.claim(@user, "name", "description", @genre, true, true)
|
||||
@recording.reload
|
||||
@claimed_recording = @recording.claimed_recordings.first
|
||||
|
||||
end
|
||||
|
||||
describe "sucessful save" do
|
||||
it "with default case" do
|
||||
valid_claimed_recording
|
||||
@claimed_recording.save.should be_true
|
||||
make_claim
|
||||
@claimed_recording.errors.any?.should be_false
|
||||
@recording.reload
|
||||
@recording.recorded_tracks.first.discard.should be_false
|
||||
end
|
||||
end
|
||||
|
||||
describe "update name" do
|
||||
it "with nil" do
|
||||
valid_claimed_recording
|
||||
@claimed_recording.name = nil
|
||||
@claimed_recording.save.should be_false
|
||||
@name = nil
|
||||
make_claim
|
||||
@claimed_recording.errors.any?.should be_true
|
||||
@claimed_recording.errors[:name].length.should == 2
|
||||
@claimed_recording.errors[:name].select { |value| value.include?("can't be blank") }.length.should == 1
|
||||
@claimed_recording.errors[:name].select { |value| value.include?("is too short") }.length.should == 1
|
||||
@recording.reload
|
||||
@recording.recorded_tracks.first.discard.should be_nil
|
||||
end
|
||||
|
||||
it "too short" do
|
||||
valid_claimed_recording
|
||||
@claimed_recording.name = "a"
|
||||
@claimed_recording.save.should be_false
|
||||
@name = "a"
|
||||
make_claim
|
||||
@claimed_recording.errors.any?.should be_true
|
||||
@claimed_recording.errors[:name].length.should == 1
|
||||
@claimed_recording.errors[:name].select { |value| value.include?("is too short") }.length.should == 1
|
||||
end
|
||||
|
|
@ -57,16 +64,18 @@ describe ClaimedRecording do
|
|||
describe "update description" do
|
||||
it "with nil" do
|
||||
valid_claimed_recording
|
||||
@claimed_recording.description = nil
|
||||
@claimed_recording.save.should be_true
|
||||
@description = nil
|
||||
make_claim
|
||||
@claimed_recording.errors.any?.should be_false
|
||||
end
|
||||
end
|
||||
|
||||
describe "update is_public" do
|
||||
it "with nil" do
|
||||
valid_claimed_recording
|
||||
@claimed_recording.is_public = nil
|
||||
@claimed_recording.save.should be_false
|
||||
@is_public = nil
|
||||
make_claim
|
||||
@claimed_recording.errors.any?.should be_true
|
||||
@claimed_recording.errors[:is_public].length.should == 1
|
||||
@claimed_recording.errors[:is_public].should == ["is not included in the list"]
|
||||
end
|
||||
|
|
@ -75,8 +84,9 @@ describe ClaimedRecording do
|
|||
describe "update is_downloadable" do
|
||||
it "with nil" do
|
||||
valid_claimed_recording
|
||||
@claimed_recording.is_downloadable = nil
|
||||
@claimed_recording.save.should be_false
|
||||
@is_downloadable = nil
|
||||
make_claim
|
||||
@claimed_recording.errors.any?.should be_true
|
||||
@claimed_recording.errors[:is_downloadable].length.should == 1
|
||||
@claimed_recording.errors[:is_downloadable].should == ["is not included in the list"]
|
||||
end
|
||||
|
|
@ -85,8 +95,9 @@ describe ClaimedRecording do
|
|||
describe "update genre" do
|
||||
it "with nil" do
|
||||
valid_claimed_recording
|
||||
@claimed_recording.genre = nil
|
||||
@claimed_recording.save.should be_false
|
||||
@genre = nil
|
||||
make_claim
|
||||
@claimed_recording.errors.any?.should be_true
|
||||
@claimed_recording.errors[:genre].length.should == 1
|
||||
@claimed_recording.errors[:genre].should == ["can't be blank"]
|
||||
end
|
||||
|
|
@ -94,6 +105,8 @@ describe ClaimedRecording do
|
|||
|
||||
describe "multiple claims" do
|
||||
it "not valid" do
|
||||
valid_claimed_recording
|
||||
make_claim
|
||||
duplicate = @recording.claim(@user, "name", "description", @genre, true, true)
|
||||
duplicate.valid?.should be_false
|
||||
duplicate.errors[:recording_id].should == ['has already been taken']
|
||||
|
|
|
|||
|
|
@ -316,6 +316,44 @@ describe Recording do
|
|||
timeline.last["end"].should == true
|
||||
end
|
||||
|
||||
describe "chance for everyone to keep or discard" do
|
||||
before(:each) do
|
||||
@user2 = FactoryGirl.create(:user)
|
||||
@connection2 = FactoryGirl.create(:connection, :user => @user2, :music_session => @music_session)
|
||||
@track2 = FactoryGirl.create(:track, :connection => @connection2, :instrument => @instrument)
|
||||
|
||||
@recording = Recording.start(@music_session, @user)
|
||||
@recording.stop
|
||||
@recording.reload
|
||||
end
|
||||
|
||||
it "no one votes" do
|
||||
@recording2 = Recording.start(@music_session, @user)
|
||||
@recording2.errors.any?.should be_true
|
||||
@recording2.errors[:music_session].should == [ValidationMessages::PREVIOUS_RECORDING_STILL_BEING_FINALIZED]
|
||||
end
|
||||
|
||||
it "only one discards" do
|
||||
@recording.discard(@user)
|
||||
@recording2 = Recording.start(@music_session, @user)
|
||||
@recording2.errors.any?.should be_true
|
||||
@recording2.errors[:music_session].should == [ValidationMessages::PREVIOUS_RECORDING_STILL_BEING_FINALIZED]
|
||||
end
|
||||
|
||||
it "everyone discards" do
|
||||
@recording.discard(@user)
|
||||
@recording.discard(@user2)
|
||||
@recording2 = Recording.start(@music_session, @user)
|
||||
@recording2.errors.any?.should be_false
|
||||
end
|
||||
|
||||
it "one discards, the other leaves the session" do
|
||||
@recording.discard(@user)
|
||||
@connection2.delete
|
||||
@recording2 = Recording.start(@music_session, @user2)
|
||||
@recording2.errors.any?.should be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -549,7 +549,7 @@
|
|||
|
||||
var possibleAnswers = ['HQ', 'RT', 'MISSING', 'PARTIALLY_MISSING'];
|
||||
|
||||
$.each(recordings.claimed_recordings, function(i, recordings) {
|
||||
$.each(recordings, function(i, recording) {
|
||||
// just make up a random yes-hq/yes-rt/missing answer
|
||||
var recordingResult = {};
|
||||
recordingResult['aggregate_state'] = possibleAnswers[Math.floor((Math.random()*4))];
|
||||
|
|
|
|||
|
|
@ -48,10 +48,10 @@
|
|||
|
||||
emptyList();
|
||||
|
||||
var recordings = [];
|
||||
var $tbody = tbody();
|
||||
|
||||
var localResults = context.jamClient.GetLocalRecordingState({claimed_recordings: claimedRecordings});
|
||||
var recordings = $.map(claimedRecordings, function(val, i) { return val.recording; });
|
||||
var localResults = context.jamClient.GetLocalRecordingState({recordings: recordings});
|
||||
|
||||
if(localResults['error']) {
|
||||
app.notify({
|
||||
|
|
@ -113,7 +113,7 @@
|
|||
rest.startPlayClaimedRecording({id: context.JK.CurrentSessionModel.id(), claimed_recording_id: claimedRecording.id})
|
||||
.done(function(response) {
|
||||
var recordingId = $(this).attr('data-recording-id');
|
||||
var openRecordingResult = context.jamClient.OpenRecording(claimedRecording);
|
||||
var openRecordingResult = context.jamClient.OpenRecording(claimedRecording.recording);
|
||||
|
||||
logger.debug("OpenRecording response: %o", openRecordingResult);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,15 +5,34 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var PlaybackMode = {
|
||||
NoPlayback: 0,
|
||||
EveryWhere: 1,
|
||||
PrivatePreview: 2,
|
||||
PreviewToAll: 3,
|
||||
LastPbMode: 4
|
||||
};
|
||||
|
||||
|
||||
|
||||
context.JK = context.JK || {};
|
||||
context.JK.PlaybackControls = function($parentElement){
|
||||
context.JK.PlaybackControls = function($parentElement, options){
|
||||
|
||||
options = $.extend(false, {playmodeControlsVisible:false}, options);
|
||||
|
||||
var logger = context.JK.logger;
|
||||
if($parentElement.length == 0) {
|
||||
logger.debug("no $parentElement specified in PlaybackControls");
|
||||
}
|
||||
|
||||
var $playButton = $('.play-button img.playbutton', $parentElement);
|
||||
var $pauseButton = $('.play-button img.pausebutton', $parentElement);
|
||||
var $currentTime = $('.recording-current', $parentElement);
|
||||
var $duration = $('.duration-time', $parentElement);
|
||||
var $sliderBar = $('.recording-playback', $parentElement);
|
||||
var $slider = $('.recording-slider', $parentElement);
|
||||
var $playmodeButton = $('.playback-mode-buttons.icheckbuttons input', $parentElement);
|
||||
|
||||
var $self = $(this);
|
||||
|
||||
var playbackPlaying = false;
|
||||
|
|
@ -26,13 +45,15 @@
|
|||
var playingWhenDragStart = false;
|
||||
var draggingUpdateTimer = null;
|
||||
var canUpdateBackend = false;
|
||||
var playbackMode = PlaybackMode.EveryWhere;
|
||||
var monitorPlaybackTimeout = null;
|
||||
|
||||
function startPlay() {
|
||||
updateIsPlaying(true);
|
||||
if(endReached) {
|
||||
update(0, playbackDurationMs, playbackPlaying);
|
||||
}
|
||||
$self.triggerHandler('play');
|
||||
$self.triggerHandler('play', {playbackMode: playbackMode});
|
||||
}
|
||||
|
||||
function stopPlay() {
|
||||
|
|
@ -94,7 +115,7 @@
|
|||
updateOffsetBasedOnPosition(offset);
|
||||
updateSliderPosition(playbackPositionMs);
|
||||
return false;
|
||||
})
|
||||
});
|
||||
|
||||
$slider.draggable({
|
||||
axis: 'x',
|
||||
|
|
@ -104,6 +125,34 @@
|
|||
drag: onDrag
|
||||
});
|
||||
|
||||
|
||||
if(options.playmodeControlsVisible) {
|
||||
$('.playback-mode-buttons.icheckbuttons', $parentElement).show();
|
||||
}
|
||||
|
||||
$playmodeButton.iCheck({
|
||||
checkboxClass: 'icheckbox_minimal',
|
||||
radioClass: 'iradio_minimal',
|
||||
inheritClass: true
|
||||
});
|
||||
|
||||
|
||||
$playmodeButton.on('ifChecked', function(e) {
|
||||
var playmode = $(this).val();
|
||||
console.log("set new playmode", playmode);
|
||||
setPlaybackMode(playmode);
|
||||
});
|
||||
|
||||
function monitorRecordingPlayback() {
|
||||
var isPlaying = context.jamClient.isSessionTrackPlaying();
|
||||
var positionMs = context.jamClient.SessionCurrrentPlayPosMs();
|
||||
var durationMs = context.jamClient.SessionGetTracksPlayDurationMs();
|
||||
|
||||
update(positionMs, durationMs, isPlaying);
|
||||
|
||||
monitorPlaybackTimeout = setTimeout(monitorRecordingPlayback, 500);
|
||||
}
|
||||
|
||||
function update(currentTimeMs, durationTimeMs, isPlaying) {
|
||||
|
||||
if(dragging) {
|
||||
|
|
@ -111,6 +160,7 @@
|
|||
}
|
||||
|
||||
// at the end of the play, the duration sets to 0, as does currentTime. but isPlaying does not reset to
|
||||
console.log("currentTimeMs, durationTimeMs", currentTimeMs, durationTimeMs);
|
||||
if(currentTimeMs == 0 && durationTimeMs == 0) {
|
||||
if(isPlaying) {
|
||||
isPlaying = false;
|
||||
|
|
@ -175,9 +225,43 @@
|
|||
}
|
||||
}
|
||||
|
||||
function setPlaybackMode(mode) {
|
||||
if(mode == 'preview-to-all') {
|
||||
playbackMode = PlaybackMode.PreviewToAll;
|
||||
}
|
||||
else if(mode == 'preview-to-me') {
|
||||
playbackMode = PlaybackMode.PrivatePreview;
|
||||
}
|
||||
else if(mode == 'eveywhere') {
|
||||
playbackMode = PlaybackMode.EveryWhere;
|
||||
}
|
||||
else {
|
||||
logger.error("unable to set playback mode", mode);
|
||||
}
|
||||
|
||||
// let the mode change immediately affect the behavior of the stream
|
||||
if(playbackPlaying) {
|
||||
stopPlay();
|
||||
startPlay();
|
||||
}
|
||||
}
|
||||
|
||||
function startMonitor() {
|
||||
monitorRecordingPlayback();
|
||||
}
|
||||
|
||||
function stopMonitor() {
|
||||
if(monitorPlaybackTimeout!= null) {
|
||||
clearTimeout(monitorPlaybackTimeout);
|
||||
monitorPlaybackTimeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.update = update;
|
||||
this.setPlaybackMode = setPlaybackMode;
|
||||
this.startMonitor = startMonitor;
|
||||
this.stopMonitor = stopMonitor;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,14 +6,22 @@
|
|||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var playbackControls = null;
|
||||
var recording = null; // deferred object
|
||||
|
||||
function resetForm() {
|
||||
|
||||
// remove all display errors
|
||||
$('#recording-finished-dialog form .error-text').remove()
|
||||
$('#recording-finished-dialog form .error').removeClass("error")
|
||||
}
|
||||
|
||||
function beforeShow() {
|
||||
if(recording == null) {
|
||||
alert("recording data should not be null");
|
||||
app.layout.closeDialog('recordingFinished');
|
||||
return false;
|
||||
}
|
||||
|
||||
resetForm();
|
||||
|
||||
var parentSelector = '#recording-finished-dialog div.genre-selector';
|
||||
|
|
@ -25,26 +33,73 @@
|
|||
var genreDescription = currentOrLastSession.genres[0];
|
||||
context.JK.GenreSelectorHelper.setSelectedGenres(parentSelector, [genreDescription]);
|
||||
}
|
||||
|
||||
var localResults = context.jamClient.GetLocalRecordingState({recordings: [recording]});
|
||||
|
||||
|
||||
if(localResults['error']) {
|
||||
app.notify({
|
||||
title : "Unable to Open Recording for Playback",
|
||||
text : localResults['error'],
|
||||
icon_url: "/assets/content/icon_alert_big.png"
|
||||
});
|
||||
}
|
||||
else {
|
||||
var localResult = localResults.recordings[0];
|
||||
if(localResult.aggregate_state == 'MISSING') {
|
||||
app.notify({
|
||||
title : "Unable to Open Recording for Playback",
|
||||
text : "All tracks associated with the recording are missing",
|
||||
icon_url: "/assets/content/icon_alert_big.png"
|
||||
});
|
||||
}
|
||||
else if(localResult.aggregate_state == 'PARTIALLY_MISSING') {
|
||||
app.notify({
|
||||
title : "Unable to Open Recording for Playback",
|
||||
text: "Some tracks associated with the recording are missing",
|
||||
icon_url: "/assets/content/icon_alert_big.png"
|
||||
})
|
||||
}
|
||||
else {
|
||||
|
||||
// load recording
|
||||
var openRecordingResult = context.jamClient.OpenRecording(recording);
|
||||
|
||||
logger.debug("OpenRecording response: %o", openRecordingResult);
|
||||
|
||||
if(openRecordingResult.error) {
|
||||
app.notify({
|
||||
"title": "Can't Open Recording",
|
||||
"text": openRecordingResult.error,
|
||||
"icon_url": "/assets/content/icon_alert_big.png"
|
||||
});
|
||||
}
|
||||
|
||||
playbackControls.startMonitor();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function afterHide() {
|
||||
|
||||
recording = null;
|
||||
playbackControls.stopMonitor();
|
||||
context.jamClient.CloseRecording();
|
||||
}
|
||||
|
||||
function discardRecording(e) {
|
||||
|
||||
resetForm();
|
||||
registerDiscardRecordingHandlers(false);
|
||||
var recordingId = JK.CurrentSessionModel.recordingModel.currentOrLastRecordingId();
|
||||
|
||||
rest.discardRecording({
|
||||
id: recordingId
|
||||
id: recording.id
|
||||
})
|
||||
.done(function() {
|
||||
console.error("recording discarded by user. recordingId=%o", recordingId);
|
||||
console.error("recording discarded by user. recordingId=%o", recording.id);
|
||||
})
|
||||
.fail(function(jqXHR){
|
||||
console.error("recording discard by user failed. recordingId=%o. reason: %o", recordingId, jqXHR.responseText);
|
||||
console.error("recording discard by user failed. recordingId=%o. reason: %o", recording.id, jqXHR.responseText);
|
||||
})
|
||||
.always(function() {
|
||||
app.layout.closeDialog('recordingFinished')
|
||||
|
|
@ -56,7 +111,6 @@
|
|||
|
||||
resetForm();
|
||||
registerClaimRecordingHandlers(false);
|
||||
var recordingId = JK.CurrentSessionModel.recordingModel.currentOrLastRecordingId();
|
||||
|
||||
var name = $('#recording-finished-dialog form input[name=name]').val();
|
||||
var description = $('#recording-finished-dialog form textarea[name=description]').val();
|
||||
|
|
@ -65,7 +119,7 @@
|
|||
var is_downloadable = $('#recording-finished-dialog form input[name=is_downloadable]').is(':checked');
|
||||
|
||||
rest.claimRecording({
|
||||
id : recordingId,
|
||||
id : recording.id,
|
||||
name: name,
|
||||
description: description,
|
||||
genre: genre,
|
||||
|
|
@ -136,12 +190,12 @@
|
|||
context.jamClient.SessionStopPlay();
|
||||
}
|
||||
|
||||
function onPlay() {
|
||||
function onPlay(e, data) {
|
||||
logger.debug("calling jamClient.SessionStartPlay");
|
||||
context.jamClient.SessionStartPlay();
|
||||
context.jamClient.SessionStartPlay(data.playbackMode);
|
||||
}
|
||||
|
||||
function onChangePlayPosition() {
|
||||
function onChangePlayPosition(e, data) {
|
||||
logger.debug("calling jamClient.SessionTrackSeekMs(" + data.positionMs + ")");
|
||||
context.jamClient.SessionTrackSeekMs(data.positionMs);
|
||||
}
|
||||
|
|
@ -155,6 +209,15 @@
|
|||
.on('change-position', onChangePlayPosition);
|
||||
}
|
||||
|
||||
function setRecording(recordingData) {
|
||||
if(recording != null) {
|
||||
//XXX - prevent start/stop recording mashing; protect this dialog
|
||||
logger.error("unable to set recording data over existing recording data. this coudld be due to start/stop recording mashing");
|
||||
return;
|
||||
}
|
||||
recording = recordingData;
|
||||
}
|
||||
|
||||
function initialize(){
|
||||
var dialogBindings = {
|
||||
'beforeShow' : beforeShow,
|
||||
|
|
@ -170,6 +233,7 @@
|
|||
|
||||
|
||||
this.initialize = initialize;
|
||||
this.setRecording = setRecording;
|
||||
}
|
||||
|
||||
return this;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
var configureTrackDialog;
|
||||
var addNewGearDialog;
|
||||
var localRecordingsDialog = null;
|
||||
var recordingFinishedDialog = null;
|
||||
var screenActive = false;
|
||||
var currentMixerRangeMin = null;
|
||||
var currentMixerRangeMax = null;
|
||||
|
|
@ -25,7 +26,6 @@
|
|||
var startingRecording = false; // double-click guard
|
||||
var claimedRecording = null;
|
||||
var playbackControls = null;
|
||||
var monitorPlaybackTimeout = null;
|
||||
|
||||
|
||||
var rest = JK.Rest();
|
||||
|
|
@ -364,16 +364,6 @@
|
|||
.fail(app.ajaxError);
|
||||
}
|
||||
|
||||
function monitorRecordingPlayback() {
|
||||
var isPlaying = context.jamClient.isSessionTrackPlaying();
|
||||
var positionMs = context.jamClient.SessionCurrrentPlayPosMs();
|
||||
var durationMs = context.jamClient.SessionGetTracksPlayDurationMs();
|
||||
|
||||
playbackControls.update(positionMs, durationMs, isPlaying);
|
||||
|
||||
monitorPlaybackTimeout = setTimeout(monitorRecordingPlayback, 500);
|
||||
}
|
||||
|
||||
function handleTransitionsInRecordingPlayback() {
|
||||
// let's see if we detect a transition to start playback or stop playback
|
||||
|
||||
|
|
@ -382,10 +372,10 @@
|
|||
if(claimedRecording == null && (currentSession && currentSession.claimed_recording != null)) {
|
||||
// this is a 'started with a claimed_recording' transition.
|
||||
// we need to start a timer to watch for the state of the play session
|
||||
monitorRecordingPlayback();
|
||||
playbackControls.startMonitor();
|
||||
}
|
||||
else if(claimedRecording && (currentSession == null || currentSession.claimed_recording == null)) {
|
||||
clearTimeout(monitorPlaybackTimeout);
|
||||
playbackControls.stopMonitor();
|
||||
}
|
||||
|
||||
claimedRecording = currentSession == null ? null : currentSession.claimed_recording;
|
||||
|
|
@ -434,7 +424,7 @@
|
|||
if ($('.session-recordings .track').length === 0) {
|
||||
$('.session-recordings .when-empty').show();
|
||||
$('.session-recording-name-wrapper').hide();
|
||||
$('.recording-controls').hide();
|
||||
$('.session-recordings .recording-controls').hide();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -917,14 +907,13 @@
|
|||
var $destination = $(parentSelector);
|
||||
$('.session-recordings .when-empty').hide();
|
||||
$('.session-recording-name-wrapper').show();
|
||||
$('.recording-controls').show();
|
||||
$('.session-recordings .recording-controls').show();
|
||||
|
||||
var template = $('#template-session-track').html();
|
||||
var newTrack = $(context.JK.fillTemplate(template, trackData));
|
||||
$destination.append(newTrack);
|
||||
if(trackData.preMasteredClass) {
|
||||
context.JK.helpBubble($('.track-instrument', newTrack), 'pre-processed-track', {}, {offsetParent: newTrack.closest('.content-body')});
|
||||
|
||||
}
|
||||
|
||||
// Render VU meters and gain fader
|
||||
|
|
@ -1247,6 +1236,7 @@
|
|||
function promptUserToSave(recordingId) {
|
||||
rest.getRecording( {id: recordingId} )
|
||||
.done(function(recording) {
|
||||
recordingFinishedDialog.setRecording(recording);
|
||||
app.layout.showDialog('recordingFinished');
|
||||
})
|
||||
.fail(app.ajaxError);
|
||||
|
|
@ -1293,9 +1283,9 @@
|
|||
context.jamClient.SessionStopPlay();
|
||||
}
|
||||
|
||||
function onPlay() {
|
||||
function onPlay(e, data) {
|
||||
logger.debug("calling jamClient.SessionStartPlay");
|
||||
context.jamClient.SessionStartPlay();
|
||||
context.jamClient.SessionStartPlay(data.playbackMode);
|
||||
}
|
||||
|
||||
function onChangePlayPosition(e, data){
|
||||
|
|
@ -1312,7 +1302,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
function events() {
|
||||
$('#session-resync').on('click', sessionResync);
|
||||
$('#session-contents').on("click", '[action="delete"]', deleteSession);
|
||||
|
|
@ -1330,13 +1319,13 @@
|
|||
.on('change-position', onChangePlayPosition);
|
||||
}
|
||||
|
||||
this.initialize = function(localRecordingsDialogInstance) {
|
||||
this.initialize = function(localRecordingsDialogInstance, recordingFinishedDialogInstance) {
|
||||
localRecordingsDialog = localRecordingsDialogInstance;
|
||||
recordingFinishedDialog = recordingFinishedDialogInstance;
|
||||
context.jamClient.SetVURefreshRate(150);
|
||||
playbackControls = new context.JK.PlaybackControls($('.session-recordings .recording-controls'));
|
||||
events();
|
||||
|
||||
|
||||
var screenBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow,
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
function recordedTracks() {
|
||||
if(currentSession && currentSession.claimed_recording) {
|
||||
return currentSession.claimed_recording.recorded_tracks
|
||||
return currentSession.claimed_recording.recording.recorded_tracks
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -111,20 +111,4 @@
|
|||
padding:10px;
|
||||
border-bottom:solid 1px #999;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
div[layout-id="createSession"] .icheckbuttons {
|
||||
|
||||
margin-top:5px;
|
||||
|
||||
div.iradio_minimal {
|
||||
float:left;
|
||||
}
|
||||
|
||||
label {
|
||||
float:left;
|
||||
margin:0 10px 0 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -460,4 +460,19 @@ div[layout-id=session], div[layout-id=ftue], .no-selection-range {
|
|||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.icheckbuttons {
|
||||
|
||||
margin-top:5px;
|
||||
|
||||
div.iradio_minimal {
|
||||
float:left;
|
||||
}
|
||||
|
||||
label {
|
||||
float:left;
|
||||
margin:0 10px 0 3px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,20 @@
|
|||
#recording-finished-dialog {
|
||||
width:1000px;
|
||||
|
||||
height:auto;
|
||||
div[purpose=description], div[purpose=is_public], div[purpose=is_downloadable] {
|
||||
margin-top:20px;
|
||||
}
|
||||
|
||||
label[for=is_downloadable], label[for=is_public] {
|
||||
label[for=is_downloadable], label[for=is_public], label[for=playback-mode-preview-all], label[for=playback-mode-preview-me] {
|
||||
display:inline;
|
||||
}
|
||||
|
||||
.recording-controls {
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.icheckbuttons {
|
||||
margin-top:20px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -491,6 +491,12 @@ table.vu td {
|
|||
background-color:#666;
|
||||
}
|
||||
|
||||
.session-mytracks {
|
||||
.track-connection {
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
|
||||
.session-recordings {
|
||||
.track-connection {
|
||||
display:none;
|
||||
|
|
@ -513,6 +519,10 @@ table.vu td {
|
|||
}
|
||||
}
|
||||
|
||||
#recording-finished-dialog .recording-controls {
|
||||
display:block;
|
||||
}
|
||||
|
||||
|
||||
.voicechat {
|
||||
margin-top:10px;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
.recording-controls {
|
||||
.playback-mode-buttons {
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
|
|
@ -24,13 +24,13 @@ class ApiClaimedRecordingsController < ApiController
|
|||
end
|
||||
|
||||
def delete
|
||||
begin
|
||||
@claimed_recording.discard(current_user)
|
||||
render :json => {}, :status => 204
|
||||
#begin
|
||||
#@claimed_recording.discard(current_user)
|
||||
#render :json => {}, :status => 204
|
||||
# respond_with responder: ApiResponder, :status => 204
|
||||
rescue
|
||||
render :json => { :message => "claimed_recording could not be deleted" }, :status => 403
|
||||
end
|
||||
#rescue
|
||||
#render :json => { :message => "claimed_recording could not be deleted" }, :status => 403
|
||||
#end
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -71,7 +71,6 @@ class ApiRecordingsController < ApiController
|
|||
# claim will create a claimed recording for the creator
|
||||
def claim
|
||||
claim = @recording.claim(current_user, params[:name], params[:description], Genre.find_by_id(params[:genre]), params[:is_public], params[:is_downloadable])
|
||||
claim.save
|
||||
|
||||
if claim.errors.any?
|
||||
response.status = :unprocessable_entity
|
||||
|
|
@ -83,8 +82,7 @@ class ApiRecordingsController < ApiController
|
|||
|
||||
# discard will tell the server the user has no interest in the recording
|
||||
def discard
|
||||
@recorded_tracks = @recording.recorded_tracks_for_user(current_user)
|
||||
RecordedTrack.update(@recorded_tracks, :discard => true)
|
||||
@recording.discard(current_user)
|
||||
render :json => {}, :status => 200
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -15,13 +15,13 @@ child(:recording => :recording) {
|
|||
child(:mixes => :mixes) {
|
||||
attributes :id, :url, :is_completed
|
||||
}
|
||||
}
|
||||
|
||||
child(:recorded_tracks => :recorded_tracks) {
|
||||
attributes :id, :fully_uploaded, :url, :client_track_id, :client_id, :instrument_id
|
||||
child(:recorded_tracks => :recorded_tracks) {
|
||||
attributes :id, :fully_uploaded, :url, :client_track_id, :client_id, :instrument_id
|
||||
|
||||
child(:user => :user) {
|
||||
attributes :id, :first_name, :last_name, :city, :state, :country, :photo_url
|
||||
child(:user => :user) {
|
||||
attributes :id, :first_name, :last_name, :city, :state, :country, :photo_url
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,13 +54,13 @@ node(:claimed_recording, :if => lambda { |music_session| music_session.users.exi
|
|||
child(:mixes => :mixes) {
|
||||
attributes :id, :url, :is_completed
|
||||
}
|
||||
}
|
||||
|
||||
child(:recorded_tracks => :recorded_tracks) {
|
||||
attributes :id, :fully_uploaded, :url, :client_track_id, :client_id, :instrument_id
|
||||
child(:recorded_tracks => :recorded_tracks) {
|
||||
attributes :id, :fully_uploaded, :url, :client_track_id, :client_id, :instrument_id
|
||||
|
||||
child(:user => :user) {
|
||||
attributes :id, :first_name, :last_name, :city, :state, :country, :photo_url
|
||||
child(:user => :user) {
|
||||
attributes :id, :first_name, :last_name, :city, :state, :country, :photo_url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,9 @@ object @recording
|
|||
attributes :id, :band, :created_at, :duration
|
||||
|
||||
child(:recorded_tracks => :recorded_tracks) {
|
||||
attributes :id, :client_id, :track_id, :user_id, :fully_uploaded, :url
|
||||
child(:instrument => :instrument) {
|
||||
attributes :id, :description
|
||||
}
|
||||
attributes :id, :fully_uploaded, :url, :client_track_id, :client_id, :instrument_id
|
||||
|
||||
child(:user => :user) {
|
||||
attributes :id, :first_name, :last_name, :city, :state, :country, :photo_url
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,5 +25,11 @@
|
|||
|
||||
<!-- current playback time -->
|
||||
<div class="recording-current">0:00</div>
|
||||
|
||||
<div class="playback-mode-buttons icheckbuttons">
|
||||
<input type="radio" name="playback-mode" checked="checked" value="preview-to-all" class="preview-to-all" /><label for="playback-mode-preview-all" class="radio-text">Preview to All</label>
|
||||
<input type="radio" name="playback-mode" value="preview-to-me" class="preview-to-me" /><label for="playback-mode-preview-me" class="radio-text">Preview Only to Me</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- end recording play controls -->
|
||||
|
|
@ -40,6 +40,7 @@
|
|||
</form>
|
||||
|
||||
<div class="left w50 ml30">
|
||||
Preview Recording:
|
||||
|
||||
<%= render "play_controls" %>
|
||||
|
||||
|
|
|
|||
|
|
@ -97,6 +97,9 @@
|
|||
var localRecordingsDialog = new JK.LocalRecordingsDialog(JK.app);
|
||||
localRecordingsDialog.initialize();
|
||||
|
||||
var recordingFinishedDialog = new JK.RecordingFinishedDialog(JK.app);
|
||||
recordingFinishedDialog.initialize();
|
||||
|
||||
var friendSelectorDialog = new JK.FriendSelectorDialog(JK.app);
|
||||
friendSelectorDialog.initialize();
|
||||
|
||||
|
|
@ -165,14 +168,11 @@
|
|||
findBandScreen.initialize();
|
||||
|
||||
var sessionScreen = new JK.SessionScreen(JK.app);
|
||||
sessionScreen.initialize(localRecordingsDialog);
|
||||
sessionScreen.initialize(localRecordingsDialog, recordingFinishedDialog);
|
||||
|
||||
var sessionSettingsDialog = new JK.SessionSettingsDialog(JK.app, sessionScreen);
|
||||
sessionSettingsDialog.initialize();
|
||||
|
||||
var recordingFinishedDialog = new JK.RecordingFinishedDialog(JK.app);
|
||||
recordingFinishedDialog.initialize();
|
||||
|
||||
var whatsNextDialog = new JK.WhatsNextDialog(JK.app);
|
||||
whatsNextDialog.initialize(invitationDialog);
|
||||
|
||||
|
|
|
|||
|
|
@ -33,11 +33,11 @@ describe ApiClaimedRecordingsController do
|
|||
json["recording"]["id"].should == @recording.id
|
||||
json["recording"]["mixes"].length.should == 0
|
||||
json["recording"]["band"].should be_nil
|
||||
json["recorded_tracks"].length.should == 1
|
||||
json["recorded_tracks"].first["id"].should == @recording.recorded_tracks.first.id
|
||||
json["recorded_tracks"].first["url"].should == @recording.recorded_tracks.first.url
|
||||
json["recorded_tracks"].first["instrument"]["id"].should == @instrument.id
|
||||
json["recorded_tracks"].first["user"]["id"].should == @user.id
|
||||
json["recording"]["recorded_tracks"].length.should == 1
|
||||
json["recording"]["recorded_tracks"].first["id"].should == @recording.recorded_tracks.first.id
|
||||
json["recording"]["recorded_tracks"].first["url"].should == @recording.recorded_tracks.first.url
|
||||
json["recording"]["recorded_tracks"].first["instrument_id"].should == @instrument.id
|
||||
json["recording"]["recorded_tracks"].first["user"]["id"].should == @user.id
|
||||
end
|
||||
|
||||
it "should show the right thing when one recording was just uploaded" do
|
||||
|
|
|
|||
Loading…
Reference in New Issue