diff --git a/db/manifest b/db/manifest index 14623b9b8..a95040283 100755 --- a/db/manifest +++ b/db/manifest @@ -249,3 +249,4 @@ recorded_backing_tracks.sql user_model_about_changes.sql performance_samples.sql user_presences.sql +recorded_backing_tracks_add_filename.sql \ No newline at end of file diff --git a/db/up/recorded_backing_tracks_add_filename.sql b/db/up/recorded_backing_tracks_add_filename.sql new file mode 100644 index 000000000..af959b9d5 --- /dev/null +++ b/db/up/recorded_backing_tracks_add_filename.sql @@ -0,0 +1 @@ +ALTER TABLE recorded_backing_tracks ADD COLUMN filename VARCHAR NOT NULL; \ No newline at end of file diff --git a/ruby/lib/jam_ruby/models/backing_track.rb b/ruby/lib/jam_ruby/models/backing_track.rb index 66304e333..7437b2de7 100644 --- a/ruby/lib/jam_ruby/models/backing_track.rb +++ b/ruby/lib/jam_ruby/models/backing_track.rb @@ -9,6 +9,7 @@ module JamRuby belongs_to :connection, :class_name => "JamRuby::Connection", :inverse_of => :tracks, :foreign_key => 'connection_id' validates :connection, presence: true validates :client_track_id, presence: true + validates :filename, presence: true def user self.connection.user diff --git a/ruby/lib/jam_ruby/models/recorded_backing_track.rb b/ruby/lib/jam_ruby/models/recorded_backing_track.rb index d3b3493ae..4d8d5ff35 100644 --- a/ruby/lib/jam_ruby/models/recorded_backing_track.rb +++ b/ruby/lib/jam_ruby/models/recorded_backing_track.rb @@ -8,11 +8,23 @@ module JamRuby def self.create_from_backing_track(backing_track, recording) recorded_backing_track = self.new recorded_backing_track.recording = recording - recorded_backing_track.client_backing_track_id = backing_track.client_backing_track_id + recorded_backing_track.client_id = backing_track.connection.client_id + recorded_backing_track.backing_track_id = backing_track.id + recorded_backing_track.client_track_id = backing_track.client_track_id recorded_backing_track.user = backing_track.connection.user - recorded_backing_track.save + recorded_backing_track.filename = backing_track.filename + recorded_backing_track.next_part_to_upload = 0 + recorded_backing_track.file_offset = 0 + recorded_backing_track[:url] = construct_filename(recording.created_at, recording.id, backing_track.client_track_id) + recorded_backing_track.save recorded_backing_track end + private + + def self.construct_filename(created_at, recording_id, client_track_id) + raise "unknown ID" unless client_track_id + "recordings/#{created_at.strftime('%m-%d-%Y')}/#{recording_id}/backing-track-#{client_track_id}.ogg" + end end end diff --git a/ruby/lib/jam_ruby/models/recording.rb b/ruby/lib/jam_ruby/models/recording.rb index ca1c241ef..cf1597ef3 100644 --- a/ruby/lib/jam_ruby/models/recording.rb +++ b/ruby/lib/jam_ruby/models/recording.rb @@ -180,6 +180,14 @@ module JamRuby recorded_tracks.where(:user_id => user.id) end + def recorded_backing_tracks_for_user(user) + unless self.users.exists?(user) + raise PermissionError, "user was not in this session" + end + recorded_backing_tracks.where(:user_id => user.id) + end + + def has_access?(user) users.exists?(user) end @@ -212,7 +220,7 @@ module JamRuby end connection.backing_tracks.each do |backing_track| - recording.recorded_videos << RecordedBackingTrack.create_from_backing_track(backing_track, recording) + recording.recorded_backing_tracks << RecordedBackingTrack.create_from_backing_track(backing_track, recording) end end end diff --git a/ruby/lib/jam_ruby/models/track.rb b/ruby/lib/jam_ruby/models/track.rb index 10b7ecb40..c06ad2d7a 100644 --- a/ruby/lib/jam_ruby/models/track.rb +++ b/ruby/lib/jam_ruby/models/track.rb @@ -55,11 +55,64 @@ module JamRuby return query end + def self.diff_track(track_class, existing_tracks, new_tracks, &blk) + result = [] + if new_tracks.length == 0 + existing_tracks.delete_all + else + + # we will prune from this as we find matching tracks + to_delete = Set.new(existing_tracks) + to_add = Array.new(new_tracks) + + existing_tracks.each do |existing_track| + new_tracks.each do |new_track| + + if new_track[:id] == existing_track.id || new_track[:client_track_id] == existing_track.client_track_id + to_delete.delete(existing_track) + to_add.delete(new_track) + + blk.call(existing_track, new_track) + + result.push(existing_track) + + if existing_track.save + next + else + result = existing_track + raise ActiveRecord::Rollback + end + end + end + end + + + to_add.each do |new_track| + existing_track = track_class.new + + blk.call(existing_track, new_track) + + if existing_track.save + result.push(existing_track) + else + result = existing_track + raise ActiveRecord::Rollback + end + end + + to_delete.each do |delete_me| + delete_me.delete + end + end + result + end # this is a bit different from a normal track synchronization in that the client just sends up all tracks, # ... some may already exist - def self.sync(clientId, tracks) - result = [] + def self.sync(clientId, tracks, backing_tracks = []) + result = {} + + backing_tracks = [] unless backing_tracks Track.transaction do connection = Connection.find_by_client_id!(clientId) @@ -68,67 +121,28 @@ module JamRuby msh = MusicSessionUserHistory.find_by_client_id!(clientId) instruments = [] - if tracks.length == 0 - connection.tracks.delete_all - else - connection_tracks = connection.tracks + tracks.each do |track| + instruments << track[:instrument_id] + end - # we will prune from this as we find matching tracks - to_delete = Set.new(connection_tracks) - to_add = Array.new(tracks) + result[:tracks] = diff_track(Track, connection.tracks, tracks) do |track_record, track_info| + track_record.connection = connection + track_record.client_track_id = track_info[:client_track_id] + track_record.client_resource_id = track_info[:client_resource_id] + track_record.instrument_id = track_info[:instrument_id] + track_record.sound = track_info[:sound] + end - tracks.each do |track| - instruments << track[:instrument_id] - end + result[:backing_tracks] = diff_track(BackingTrack, connection.backing_tracks, backing_tracks) do |track_record, track_info| + track_record.connection = connection + track_record.client_track_id = track_info[:client_track_id] + track_record.client_resource_id = track_info[:client_resource_id] + track_record.filename = track_info[:filename] + end - connection_tracks.each do |connection_track| - tracks.each do |track| - - if track[:id] == connection_track.id || track[:client_track_id] == connection_track.client_track_id - to_delete.delete(connection_track) - to_add.delete(track) - # don't update connection_id or client_id; it's unknown what would happen if these changed mid-session - connection_track.instrument_id = track[:instrument_id] - connection_track.sound = track[:sound] - connection_track.client_track_id = track[:client_track_id] - connection_track.client_resource_id = track[:client_resource_id] - - result.push(connection_track) - - if connection_track.save - next - else - result = connection_track - raise ActiveRecord::Rollback - end - - end - end - end - - msh.instruments = instruments.join("|") - if !msh.save - raise ActiveRecord::Rollback - end - - to_add.each do |track| - connection_track = Track.new - connection_track.connection = connection - connection_track.instrument_id = track[:instrument_id] - connection_track.sound = track[:sound] - connection_track.client_track_id = track[:client_track_id] - connection_track.client_resource_id = track[:client_resource_id] - if connection_track.save - result.push(connection_track) - else - result = connection_track - raise ActiveRecord::Rollback - end - end - - to_delete.each do |delete_me| - delete_me.delete - end + msh.instruments = instruments.join("|") + if !msh.save + raise ActiveRecord::Rollback end end diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index 30bde5246..3bb4c270a 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -122,6 +122,7 @@ module JamRuby # saved tracks has_many :recorded_tracks, :foreign_key => "user_id", :class_name => "JamRuby::RecordedTrack", :inverse_of => :user has_many :recorded_videos, :foreign_key => "user_id", :class_name => "JamRuby::RecordedVideo", :inverse_of => :user + has_many :recorded_backing_tracks, :foreign_key => "user_id", :class_name => "JamRuby::RecordedBackingTrack", :inverse_of => :user has_many :quick_mixes, :foreign_key => "user_id", :class_name => "JamRuby::QuickMix", :inverse_of => :user # invited users diff --git a/ruby/spec/jam_ruby/models/recording_spec.rb b/ruby/spec/jam_ruby/models/recording_spec.rb index a151bb43f..d2fd7c3b0 100644 --- a/ruby/spec/jam_ruby/models/recording_spec.rb +++ b/ruby/spec/jam_ruby/models/recording_spec.rb @@ -211,6 +211,20 @@ describe Recording do user1_recorded_tracks[0].discard = true user1_recorded_tracks[0].save! end + + it "should allow finding of backing tracks" do + user2 = FactoryGirl.create(:user) + connection2 = FactoryGirl.create(:connection, :user => user2, :music_session => @music_session) + track2 = FactoryGirl.create(:track, :connection => connection2, :instrument => @instrument) + backing_track = FactoryGirl.create(:backing_track, :connection => connection2) + + + @recording = Recording.start(@music_session, @user) + @recording.recorded_backing_tracks_for_user(@user).length.should eq(0) + user2_recorded_tracks = @recording.recorded_backing_tracks_for_user(user2) + user2_recorded_tracks.length.should == 1 + user2_recorded_tracks[0].should == user2.recorded_backing_tracks[0] + end it "should set up the recording properly when recording is started with 1 user in the session" do @music_session.is_recording?.should be_false diff --git a/ruby/spec/jam_ruby/models/track_spec.rb b/ruby/spec/jam_ruby/models/track_spec.rb index 1e03d123b..4b27ad062 100644 --- a/ruby/spec/jam_ruby/models/track_spec.rb +++ b/ruby/spec/jam_ruby/models/track_spec.rb @@ -7,8 +7,10 @@ describe Track do let (:connection) { FactoryGirl.create(:connection, :user => user, :music_session => music_session) } let (:track) { FactoryGirl.create(:track, :connection => connection)} let (:track2) { FactoryGirl.create(:track, :connection => connection)} + let (:backing_track) { FactoryGirl.create(:backing_track, :connection => connection)} let (:msuh) {FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => user, :client_id => connection.client_id) } let (:track_hash) { {:client_track_id => 'client_guid', :sound => 'stereo', :instrument_id => 'drums'} } + let (:backing_track_hash) { {:client_track_id => 'client_guid', :filename => "blah.wav"} } before(:each) do msuh.touch @@ -16,7 +18,8 @@ describe Track do describe "sync" do it "create one track" do - tracks = Track.sync(connection.client_id, [track_hash]) + result = Track.sync(connection.client_id, [track_hash]) + tracks = result[:tracks] tracks.length.should == 1 track = tracks[0] track.client_track_id.should == track_hash[:client_track_id] @@ -25,7 +28,8 @@ describe Track do end it "create two tracks" do - tracks = Track.sync(connection.client_id, [track_hash, track_hash]) + result = Track.sync(connection.client_id, [track_hash, track_hash]) + tracks = result[:tracks] tracks.length.should == 2 track = tracks[0] track.client_track_id.should == track_hash[:client_track_id] @@ -40,7 +44,8 @@ describe Track do it "delete only track" do track.id.should_not be_nil connection.tracks.length.should == 1 - tracks = Track.sync(connection.client_id, []) + result = Track.sync(connection.client_id, []) + tracks = result[:tracks] tracks.length.should == 0 end @@ -49,7 +54,8 @@ describe Track do track.id.should_not be_nil track2.id.should_not be_nil connection.tracks.length.should == 2 - tracks = Track.sync(connection.client_id, [{:id => track.id, :client_track_id => 'client_guid_new', :sound => 'mono', :instrument_id => 'drums'}]) + result = Track.sync(connection.client_id, [{:id => track.id, :client_track_id => 'client_guid_new', :sound => 'mono', :instrument_id => 'drums'}]) + tracks = result[:tracks] tracks.length.should == 1 found = tracks[0] found.id.should == track.id @@ -62,7 +68,8 @@ describe Track do track.id.should_not be_nil track2.id.should_not be_nil connection.tracks.length.should == 2 - tracks = Track.sync(connection.client_id, [{:client_track_id => track.client_track_id, :sound => 'mono', :instrument_id => 'drums'}]) + result = Track.sync(connection.client_id, [{:client_track_id => track.client_track_id, :sound => 'mono', :instrument_id => 'drums'}]) + tracks = result[:tracks] tracks.length.should == 1 found = tracks[0] found.id.should == track.id @@ -75,7 +82,8 @@ describe Track do track.id.should_not be_nil connection.tracks.length.should == 1 set_updated_at(track, 1.days.ago) - tracks = Track.sync(connection.client_id, [{:id => track.id, :client_track_id => 'client_guid_new', :sound => 'mono', :instrument_id => 'drums'}]) + result = Track.sync(connection.client_id, [{:id => track.id, :client_track_id => 'client_guid_new', :sound => 'mono', :instrument_id => 'drums'}]) + tracks = result[:tracks] tracks.length.should == 1 found = tracks[0] found.id.should == track.id @@ -87,7 +95,8 @@ describe Track do it "updates a single track using .client_track_id to correlate" do track.id.should_not be_nil connection.tracks.length.should == 1 - tracks = Track.sync(connection.client_id, [{:client_track_id => track.client_track_id, :sound => 'mono', :instrument_id => 'drums'}]) + result = Track.sync(connection.client_id, [{:client_track_id => track.client_track_id, :sound => 'mono', :instrument_id => 'drums'}]) + tracks = result[:tracks] tracks.length.should == 1 found = tracks[0] found.id.should == track.id @@ -99,11 +108,69 @@ describe Track do track.id.should_not be_nil connection.tracks.length.should == 1 set_updated_at(track, 1.days.ago) - tracks = Track.sync(connection.client_id, [{:id => track.id, :client_track_id => track.client_track_id, :sound => track.sound, :instrument_id => track.instrument_id, client_resource_id: track.client_resource_id}]) + result = Track.sync(connection.client_id, [{:id => track.id, :client_track_id => track.client_track_id, :sound => track.sound, :instrument_id => track.instrument_id, client_resource_id: track.client_resource_id}]) + tracks = result[:tracks] tracks.length.should == 1 found = tracks[0] expect(found.id).to eq track.id expect(found.updated_at.to_i).to eq track.updated_at.to_i end + + describe "backing tracks" do + it "create one track and one backing track" do + result = Track.sync(connection.client_id, [track_hash], [backing_track_hash]) + tracks = result[:tracks] + tracks.length.should == 1 + track = tracks[0] + track.client_track_id.should == track_hash[:client_track_id] + track.sound = track_hash[:sound] + track.instrument.should == Instrument.find('drums') + + backing_tracks = result[:backing_tracks] + backing_tracks.length.should == 1 + track = backing_tracks[0] + track.client_track_id.should == backing_track_hash[:client_track_id] + end + + it "delete only backing_track" do + track.id.should_not be_nil + backing_track.id.should_not be_nil + connection.tracks.length.should == 1 + connection.backing_tracks.length.should == 1 + result = Track.sync(connection.client_id, + [{:id => track.id, :client_track_id => track.client_track_id, :sound => track.sound, :instrument_id => track.instrument_id, client_resource_id: track.client_resource_id}], + []) + tracks = result[:tracks] + tracks.length.should == 1 + found = tracks[0] + expect(found.id).to eq track.id + expect(found.updated_at.to_i).to eq track.updated_at.to_i + + backing_tracks = result[:backing_tracks] + backing_tracks.length.should == 0 + end + + it "does not touch updated_at when nothing changes" do + track.id.should_not be_nil + backing_track.id.should_not be_nil + connection.tracks.length.should == 1 + set_updated_at(track, 1.days.ago) + set_updated_at(backing_track, 1.days.ago) + result = Track.sync(connection.client_id, + [{:id => track.id, :client_track_id => track.client_track_id, :sound => track.sound, :instrument_id => track.instrument_id, client_resource_id: track.client_resource_id}], + [{:id => backing_track.id, :client_track_id => backing_track.client_track_id, :filename => backing_track.filename, client_resource_id: backing_track.client_resource_id}]) + tracks = result[:tracks] + tracks.length.should == 1 + found = tracks[0] + expect(found.id).to eq track.id + expect(found.updated_at.to_i).to eq track.updated_at.to_i + + backing_tracks = result[:backing_tracks] + backing_tracks.length.should == 1 + found = backing_tracks[0] + expect(found.id).to eq backing_track.id + expect(found.updated_at.to_i).to eq backing_track.updated_at.to_i + end + end end end \ No newline at end of file diff --git a/web/app/assets/javascripts/dialog/openBackingTrackDialog.js b/web/app/assets/javascripts/dialog/openBackingTrackDialog.js index b1297c2e1..309084c82 100644 --- a/web/app/assets/javascripts/dialog/openBackingTrackDialog.js +++ b/web/app/assets/javascripts/dialog/openBackingTrackDialog.js @@ -46,18 +46,19 @@ function getBackingTracks(page) { - var backingTracks = context.jamClient.getBackingTrackList(); - console.log("Backing Tracks: ", backingTracks) + var result = context.jamClient.getBackingTrackList(); + console.log("result", result) + var backingTracks = result.backing_tracks; - if (typeof(backingTracks)=="undefined") { + if (!backingTracks || backingTracks.length == 0) { $tbody.append("