diff --git a/pb/src/client_container.proto b/pb/src/client_container.proto index 0169de05e..9e16de1f4 100644 --- a/pb/src/client_container.proto +++ b/pb/src/client_container.proto @@ -42,6 +42,7 @@ message ClientMessage { RECORDING_STARTED = 210; RECORDING_ENDED = 215; RECORDING_MASTER_MIX_COMPLETE = 220; + DOWNLOAD_AVAILABLE = 221; // band notifications BAND_INVITATION = 225; @@ -109,6 +110,7 @@ message ClientMessage { optional RecordingStarted recording_started = 210; optional RecordingEnded recording_ended = 215; optional RecordingMasterMixComplete recording_master_mix_complete = 220; + optional DownloadAvailable download_available = 221; // band notifications optional BandInvitation band_invitation = 225; @@ -330,6 +332,10 @@ message RecordingMasterMixComplete { optional string created_at = 4; } +message DownloadAvailable { + +} + message BandInvitation { optional string band_invitation_id = 1; optional string band_id = 2; diff --git a/ruby/config/resque.yml b/ruby/config/resque.yml new file mode 100644 index 000000000..834aace2c --- /dev/null +++ b/ruby/config/resque.yml @@ -0,0 +1,2 @@ +test: + redis: localhost:6379 \ No newline at end of file diff --git a/ruby/lib/jam_ruby.rb b/ruby/lib/jam_ruby.rb index 1f16a8104..306042a5a 100755 --- a/ruby/lib/jam_ruby.rb +++ b/ruby/lib/jam_ruby.rb @@ -27,6 +27,7 @@ require "jam_ruby/lib/module_overrides" require "jam_ruby/lib/s3_util" require "jam_ruby/lib/s3_manager" require "jam_ruby/lib/profanity" +require "jam_ruby/resque/audiomixer" require "jam_ruby/mq_router" require "jam_ruby/base_manager" require "jam_ruby/connection_manager" diff --git a/ruby/lib/jam_ruby/lib/audiomixer.rb b/ruby/lib/jam_ruby/lib/audiomixer.rb deleted file mode 100644 index 2efc0c955..000000000 --- a/ruby/lib/jam_ruby/lib/audiomixer.rb +++ /dev/null @@ -1,21 +0,0 @@ -require 'json' -require 'resque' - -module JamRuby - - @queue = :audiomixer - - class AudioMixer - - def self.perform(manifest) - tmp = Dir::Tmpname.make_tmpname "/var/tmp/audiomixer/manifest-#{manifest['recordingId']}", nil - File.open(tmp,"w") do |f| - f.write(manifest.to_json) - end - - system("tar zxvf some_big_tarball.tar.gz")) - end - - end - -end \ No newline at end of file diff --git a/ruby/lib/jam_ruby/lib/s3_manager.rb b/ruby/lib/jam_ruby/lib/s3_manager.rb index 66a882ebd..a5c543755 100644 --- a/ruby/lib/jam_ruby/lib/s3_manager.rb +++ b/ruby/lib/jam_ruby/lib/s3_manager.rb @@ -19,8 +19,8 @@ module JamRuby "s3://#{@aws_bucket}/#{filename}" end - def url(filename) - "https://s3.amazonaws.com/#{@aws_bucket}/#{filename}" + def url(filename, options = @@def_opts) + "http#{options[:secure] ? "s" : ""}://s3.amazonaws.com/#{@aws_bucket}/#{filename}" end def upload_sign(filename, content_md5, part_number, upload_id) diff --git a/ruby/lib/jam_ruby/message_factory.rb b/ruby/lib/jam_ruby/message_factory.rb index 7bdcb0881..24b8ddcff 100644 --- a/ruby/lib/jam_ruby/message_factory.rb +++ b/ruby/lib/jam_ruby/message_factory.rb @@ -70,6 +70,16 @@ module JamRuby ) end + def download_available + download_available = Jampb::DownloadAvailable.new + + return Jampb::ClientMessage.new( + :type => ClientMessage::Type::DOWNLOAD_AVAILABLE, + :route_to => CLIENT_TARGET, + :download_available => download_available + ) + end + # create a music session login message def login_music_session(music_session) login_music_session = Jampb::LoginMusicSession.new(:music_session => music_session) diff --git a/ruby/lib/jam_ruby/models/notification.rb b/ruby/lib/jam_ruby/models/notification.rb index 220b9bfd9..127b761ac 100644 --- a/ruby/lib/jam_ruby/models/notification.rb +++ b/ruby/lib/jam_ruby/models/notification.rb @@ -740,6 +740,13 @@ module JamRuby @@mq_router.server_publish_to_session(music_session, msg, sender = {:client_id => client_id}) end + + + def send_download_available(user_id) + msg = @@message_factory.download_available + + @@mq_router.publish_to_user(user_id, msg) + end end end end \ No newline at end of file diff --git a/ruby/lib/jam_ruby/models/recorded_track.rb b/ruby/lib/jam_ruby/models/recorded_track.rb index f56bbd335..53302a141 100644 --- a/ruby/lib/jam_ruby/models/recorded_track.rb +++ b/ruby/lib/jam_ruby/models/recorded_track.rb @@ -86,7 +86,7 @@ module JamRuby recorded_track.next_part_to_upload = 0 recorded_track.file_offset = 0 recorded_track.save - recorded_track.url = construct_filename(recording.id, track.id) + recorded_track.url = construct_filename(recording.id, track.client_track_id) recorded_track.save recorded_track end @@ -160,12 +160,12 @@ module JamRuby def filename # construct a path for s3 - RecordedTrack.construct_filename(self.recording.id, self.track_id) + RecordedTrack.construct_filename(self.recording.id, self.client_track_id) end - def self.construct_filename(recording_id, track_id) - raise "unknown ID" unless track_id - "recordings/#{recording_id}/track-#{track_id}.ogg" + def self.construct_filename(recording_id, client_track_id) + raise "unknown ID" unless client_track_id + "recordings/#{recording_id}/track-#{client_track_id}.ogg" end end end diff --git a/ruby/lib/jam_ruby/models/recorded_track_observer.rb b/ruby/lib/jam_ruby/models/recorded_track_observer.rb index c8392f4cb..8ad806704 100644 --- a/ruby/lib/jam_ruby/models/recorded_track_observer.rb +++ b/ruby/lib/jam_ruby/models/recorded_track_observer.rb @@ -5,6 +5,8 @@ module JamRuby observe JamRuby::RecordedTrack def before_validation(recorded_track) + + # if we see that a part was just uploaded entirely, validate that we can find the part that was just uploaded if recorded_track.is_part_uploading_was && !recorded_track.is_part_uploading begin aws_part = recorded_track.s3_manager.multiple_upload_find_part(recorded_track.url, recorded_track.upload_id, recorded_track.next_part_to_upload - 1) @@ -22,10 +24,13 @@ module JamRuby end - # if we detect that this just became fully uploaded + # if we detect that this just became fully uploaded -- if so, tell s3 to put the parts together if !recorded_track.fully_uploaded_was && recorded_track.fully_uploaded + + multipart_success = false begin recorded_track.s3_manager.multipart_upload_complete(recorded_track.url, recorded_track.upload_id) + multipart_success = true rescue SocketError => e raise # this should cause a 500 error, which is what we want. The client will retry later. rescue Exception => e @@ -34,6 +39,11 @@ module JamRuby recorded_track.errors.add(:upload_id, ValidationMessages::BAD_UPLOAD) end + # tell all users that a download is available, except for the user who just uploaded + recorded_track.recording.users.each do |user| + Notification.send_download_available(recorded_track.user_id) unless user == recorded_track.user + end + end end @@ -41,6 +51,7 @@ module JamRuby end + # here we tick upload failure counts, or revert the state of the model, as needed def after_rollback(recorded_track) # if fully uploaded, don't increment failures if recorded_track.fully_uploaded diff --git a/ruby/lib/jam_ruby/models/recording.rb b/ruby/lib/jam_ruby/models/recording.rb index ac1fa2f29..f96d4e23d 100644 --- a/ruby/lib/jam_ruby/models/recording.rb +++ b/ruby/lib/jam_ruby/models/recording.rb @@ -163,53 +163,45 @@ module JamRuby # ":recordings =>" part, you'll just get the recorded_tracks that I played. Very different! # we also only allow you to be told about downloads if you have claimed the recording - User.joins(:recordings).joins(:recordings => :recorded_tracks).joins(:recordings => :claimed_recordings) - .order(%Q{ recorded_tracks.id }) - .where(%Q{ recorded_tracks.fully_uploaded = TRUE }) + #User.joins(:recordings).joins(:recordings => :recorded_tracks).joins(:recordings => :claimed_recordings) + RecordedTrack.joins(:recording).joins(:recording => :claimed_recordings) + .order('recorded_tracks.id') + .where('recorded_tracks.fully_uploaded = TRUE') .where('recorded_tracks.id > ?', since) - .where('claimed_recordings.user_id = ?', user) - .where(:id => user.id).limit(limit).each do |theuser| - theuser.recordings.each do |recording| - recording.recorded_tracks.each do |recorded_track| - downloads.push( - { - :type => "recorded_track", - :id => recorded_track.client_track_id, - :recording_id => recording.id, - :length => recorded_track.length, - :md5 => recorded_track.md5, - :url => recorded_track.url, - :next => recorded_track.id - } - ) - end - end + .where('claimed_recordings.user_id = ?', user).limit(limit).each do |recorded_track| + downloads.push( + { + :type => "recorded_track", + :id => recorded_track.client_track_id, + :recording_id => recorded_track.recording_id, + :length => recorded_track.length, + :md5 => recorded_track.md5, + :url => recorded_track.url, + :next => recorded_track.id + } + ) end latest_recorded_track = downloads[-1][:next] if downloads.length > 0 - User.joins(:recordings).joins(:recordings => :mixes) + Mix.joins(:recording).joins(:recording => :claimed_recordings) .order('mixes.id') .where('mixes.completed_at IS NOT NULL') .where('mixes.id > ?', since) - .where(:id => user.id) - .limit(limit).each do |theuser| - theuser.recordings.each do |recording| - recording.mixes.each do |mix| - downloads.push( - { - :type => "mix", - :id => mix.id, - :recording_id => recording.id, - :length => mix.length, - :md5 => mix.md5, - :url => mix.url, - :created_at => mix.created_at, - :next => mix.id - } - ) - end - end + .where('claimed_recordings.user_id = ?', user) + .limit(limit).each do |mix| + downloads.push( + { + :type => "mix", + :id => mix.id, + :recording_id => mix.recording_id, + :length => mix.length, + :md5 => mix.md5, + :url => mix.url, + :created_at => mix.created_at, + :next => mix.id + } + ) end latest_mix = downloads[-1][:next] if downloads.length > 0 diff --git a/ruby/lib/jam_ruby/resque/audiomixer.rb b/ruby/lib/jam_ruby/resque/audiomixer.rb new file mode 100644 index 000000000..850c9f9a7 --- /dev/null +++ b/ruby/lib/jam_ruby/resque/audiomixer.rb @@ -0,0 +1,32 @@ +require 'json' +require 'resque' + +module JamRuby + + @queue = :audiomixer + + class AudioMixer + + def self.perform(manifest) + audiomixer = AudioMixer.new + audiomixer.run(manifest) + + end + + def run(manifest) + manifest_file = Dir::Tmpname.make_tmpname "/var/tmp/audiomixer/manifest-#{manifest['recordingId']}", nil + File.open(manifest_file,"w") do |f| + f.write(manifest.to_json) + end + + #{"files": [{"codec": "vorbis", "offset": 0, "filename": "TPD - bass.flac-stereo.ogg"}, {"codec": "vorbis", "offset": 0, "filename": "TPD - bg vox.flac-stereo.ogg"}, {"codec": "vorbis", "offset": 0, "filename": "TPD - drums.flac-stereo.ogg"}, {"codec": "vorbis", "offset": 0, "filename": "TPD - guitars.flac-stereo.ogg"}, {"codec": "vorbis", "offset": 0, "filename": "TPD - lead vox.flac-stereo.ogg"}], "output": {"codec": "vorbis", "filename": "mix.ogg"}, "timeline": [{"timestamp": 0, "mix": [{"balance": 0, "level": 100}, {"balance": 0, "level": 100}, {"balance": 0, "level": 100}, {"balance": 0, "level": 100}, {"balance": 0, "level": 100}]}]} + + path = "/var/lib/audiomixer/audiomixer/audiomixerapp" + + system("tar zxvf some_big_tarball.tar.gz") + + end + + end + +end \ No newline at end of file diff --git a/ruby/spec/jam_ruby/lib/s3_util_spec.rb b/ruby/spec/jam_ruby/lib/s3_util_spec.rb deleted file mode 100644 index d0dbb07d9..000000000 --- a/ruby/spec/jam_ruby/lib/s3_util_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -require 'spec_helper' - -describe S3Util do - - describe "sign_url" do - pending - it "returns something" do - S3Util.sign_url("jamkazam-dev", "avatar-tmp/user/image.png").should_not be_nil - end - end - -end - diff --git a/ruby/spec/jam_ruby/models/mix_spec.rb b/ruby/spec/jam_ruby/models/mix_spec.rb index 3c902b492..2053bf1c8 100755 --- a/ruby/spec/jam_ruby/models/mix_spec.rb +++ b/ruby/spec/jam_ruby/models/mix_spec.rb @@ -11,7 +11,8 @@ describe Mix do @music_session.save @recording = Recording.start(@music_session, @user) @recording.stop - @recording.claim(@user, "name", "description", Genre.first, true, true) + @recording.claim(@user, "name", "description", Genre.first, true, true) + @recording.errors.any?.should be_false @mix = Mix.schedule(@recording, "{}") end diff --git a/ruby/spec/jam_ruby/models/recorded_track_spec.rb b/ruby/spec/jam_ruby/models/recorded_track_spec.rb index e77ae5e92..ed2b74701 100644 --- a/ruby/spec/jam_ruby/models/recorded_track_spec.rb +++ b/ruby/spec/jam_ruby/models/recorded_track_spec.rb @@ -42,7 +42,7 @@ describe RecordedTrack do it "gets a url for the track" do @recorded_track = RecordedTrack.create_from_track(@track, @recording) @recorded_track.save.should be_true - @recorded_track.url.should == "recordings/#{@recording.id}/track-#{@track.id}.ogg" + @recorded_track.url.should == "recordings/#{@recording.id}/track-#{@track.client_track_id}.ogg" end it "signs url" do diff --git a/ruby/spec/jam_ruby/models/recording_spec.rb b/ruby/spec/jam_ruby/models/recording_spec.rb index 6cbb0147c..7f34bb2c3 100644 --- a/ruby/spec/jam_ruby/models/recording_spec.rb +++ b/ruby/spec/jam_ruby/models/recording_spec.rb @@ -230,6 +230,7 @@ describe Recording do downloads["downloads"].length.should == 1 end + it "should return a file list for a user properly" do pending stub_const("APP_CONFIG", app_config) diff --git a/ruby/spec/support/utilities.rb b/ruby/spec/support/utilities.rb index 9a22c1b8d..dfc0d8c1d 100644 --- a/ruby/spec/support/utilities.rb +++ b/ruby/spec/support/utilities.rb @@ -23,9 +23,7 @@ def wipe_s3_test_bucket s3 = AWS::S3.new(:access_key_id => test_config.aws_access_key_id, :secret_access_key => test_config.aws_secret_access_key) test_bucket = s3.buckets[JAMKAZAM_TESTING_BUCKET] - if test_bucket.name == JAMKAZAM_TESTING_BUCKET - puts "Ruby - Pretending to delete all contents of #{test_bucket.name}" - #test_bucket.delete_all + #test_bucket.clear! end end \ No newline at end of file diff --git a/web/app/assets/javascripts/AAB_message_factory.js b/web/app/assets/javascripts/AAB_message_factory.js index e45d11c86..b6820a8b1 100644 --- a/web/app/assets/javascripts/AAB_message_factory.js +++ b/web/app/assets/javascripts/AAB_message_factory.js @@ -42,6 +42,7 @@ RECORDING_STARTED : "RECORDING_STARTED", RECORDING_ENDED : "RECORDING_ENDED", RECORDING_MASTER_MIX_COMPLETE : "RECORDING_MASTER_MIX_COMPLETE", + DOWNLOAD_AVAILABLE : "DOWNLOAD_AVAILABLE", // band notifications BAND_INVITATION : "BAND_INVITATION", diff --git a/web/app/assets/javascripts/fakeJamClient.js b/web/app/assets/javascripts/fakeJamClient.js index 6adcc1c96..96ee3781c 100644 --- a/web/app/assets/javascripts/fakeJamClient.js +++ b/web/app/assets/javascripts/fakeJamClient.js @@ -283,6 +283,10 @@ ]; } + function RegisterRecordingManagerCallbacks(commandStart, commandProgress, commandStop, commandsChanged) { + + } + function RegisterRecordingCallbacks(startRecordingCallbackName, stopRecordingCallbackName, startedRecordingCallbackName, stoppedRecordingCallbackName, abortedRecordingCallbackName) { fakeJamClientRecordings.RegisterRecordingCallbacks(startRecordingCallbackName, stopRecordingCallbackName, startedRecordingCallbackName,stoppedRecordingCallbackName, abortedRecordingCallbackName); } @@ -565,6 +569,7 @@ return {success: true} } function CloseRecording() {} + function OnDownloadAvailable() {} // Javascript Bridge seems to camel-case @@ -633,6 +638,7 @@ this.SessionAddTrack = SessionAddTrack; this.SessionGetControlState = SessionGetControlState; this.SessionGetIDs = SessionGetIDs; + this.RegisterRecordingManagerCallbacks = RegisterRecordingManagerCallbacks; this.RegisterRecordingCallbacks = RegisterRecordingCallbacks; this.SessionRegisterCallback = SessionRegisterCallback; this.SessionSetAlertCallback = SessionSetAlertCallback; @@ -695,6 +701,7 @@ this.GetLocalRecordingState = GetLocalRecordingState; this.OpenRecording = OpenRecording; this.CloseRecording = CloseRecording; + this.OnDownloadAvailable = OnDownloadAvailable; // fake calls; not a part of the actual jam client this.RegisterP2PMessageCallbacks = RegisterP2PMessageCallbacks; diff --git a/web/app/assets/javascripts/findMusician.js b/web/app/assets/javascripts/findMusician.js index 16742bafe..cdd36acb0 100644 --- a/web/app/assets/javascripts/findMusician.js +++ b/web/app/assets/javascripts/findMusician.js @@ -1,15 +1,15 @@ (function(context,$) { - "use strict"; + "use strict"; - context.JK = context.JK || {}; - context.JK.FindMusicianScreen = function(app) { + context.JK = context.JK || {}; + context.JK.FindMusicianScreen = function(app) { var logger = context.JK.logger; var musicians = {}; var musicianList; var instrument_logo_map = context.JK.getInstrumentIconMap24(); - var did_show_musician_page = false; - var page_num=1, page_count=0; + var did_show_musician_page = false; + var page_num=1, page_count=0; function loadMusicians(queryString) { // squelch nulls and undefines @@ -24,157 +24,165 @@ } function search() { - did_show_musician_page = true; + did_show_musician_page = true; var queryString = 'srch_m=1&page='+page_num+'&'; // order by - var orderby = $('#musician_order_by').val(); + var orderby = $('#musician_order_by').val(); if (typeof orderby != 'undefined' && orderby.length > 0) { queryString += "orderby=" + orderby + '&'; } + // instrument filter - var instrument = $('#musician_instrument').val(); + var instrument = $('#musician_instrument').val(); if (typeof instrument != 'undefined' && !(instrument === '')) { queryString += "instrument=" + instrument + '&'; } + // distance filter var query_param = $('#musician_query_distance').val(); if (query_param !== null && query_param.length > 0) { - var matches = query_param.match(/(\d+)/); - if (0 < matches.length) { - var distance = matches[0]; - queryString += "distance=" + distance + '&'; - } + var matches = query_param.match(/(\d+)/); + if (0 < matches.length) { + var distance = matches[0]; + queryString += "distance=" + distance + '&'; + } } loadMusicians(queryString); } function refreshDisplay() { - clearResults(); - search(); + clearResults(); + search(); } function afterLoadMusicians(mList) { // display the 'no musicians' banner if appropriate var $noMusiciansFound = $('#musicians-none-found'); - musicianList = mList; + musicianList = mList; if(musicianList.length == 0) { $noMusiciansFound.show(); - musicians = []; - } else { + musicians = []; + } + else { $noMusiciansFound.hide(); - musicians = musicianList['musicians']; - if (!(typeof musicians === 'undefined')) { - $('#musician-filter-city').text(musicianList['city']); - if (0 == page_count) { - page_count = musicianList['page_count']; - } - renderMusicians(); - } + musicians = musicianList['musicians']; + if (!(typeof musicians === 'undefined')) { + $('#musician-filter-city').text(musicianList['city']); + if (0 == page_count) { + page_count = musicianList['page_count']; + } + renderMusicians(); + } } } - /** - * Render a list of musicians - */ function renderMusicians() { var ii, len; - var mTemplate = $('#template-find-musician-row').html(); - var fTemplate = $('#template-musician-follow-info').html(); - var aTemplate = $('#template-musician-action-btns').html(); - var mVals, mm, renderings=''; - var instr_logos, instr; - var follows, followVals, aFollow; - - for (ii=0, len=musicians.length; ii < len; ii++) { - mm = musicians[ii]; - instr_logos = ''; - for (var jj=0, ilen=mm['instruments'].length; jj '; - } - follows = ''; - followVals = {}; - for (var jj=0, ilen=mm['followings'].length; jj= $(this)[0].scrollHeight) { - if (page_num < page_count) { - page_num += 1; - search(); - } + if (page_num < page_count) { + page_num += 1; + search(); + } } }); } - /** - * Initialize, - */ function initialize() { var screenBindings = { 'beforeShow': beforeShow, @@ -231,5 +236,4 @@ return this; }; - })(window,jQuery); diff --git a/web/app/assets/javascripts/jamkazam.js b/web/app/assets/javascripts/jamkazam.js index dd5fef42b..d9ec02fba 100644 --- a/web/app/assets/javascripts/jamkazam.js +++ b/web/app/assets/javascripts/jamkazam.js @@ -130,6 +130,13 @@ } } + /** + * This occurs when a new download from a recording has become available + */ + function downloadAvailable() { + context.jamClient.OnDownloadAvailable(); + } + /** * Called whenever the websocket closes; this gives us a chance to cleanup things that should be stopped/cleared * @param in_error did the socket close abnormally? @@ -172,6 +179,12 @@ context.JK.JamServer.registerMessageCallback(context.JK.MessageType.SERVER_BAD_STATE_RECOVERED, serverBadStateRecovered); } + function registerDownloadAvailable() { + logger.debug("register for download_available"); + context.JK.JamServer.registerMessageCallback(context.JK.MessageType.DOWNLOAD_AVAILABLE, downloadAvailable); + } + + function registerSocketClosed() { logger.debug("register for socket closed"); context.JK.JamServer.registerOnSocketClosed(socketClosed); @@ -346,6 +359,7 @@ registerBadStateRecovered(); registerBadStateError(); registerSocketClosed(); + registerDownloadAvailable(); context.JK.FaderHelpers.initialize(); context.window.onunload = this.unloadFunction; } diff --git a/web/app/assets/javascripts/playbackControls.js b/web/app/assets/javascripts/playbackControls.js index 79282670d..cf1df1323 100644 --- a/web/app/assets/javascripts/playbackControls.js +++ b/web/app/assets/javascripts/playbackControls.js @@ -1,5 +1,5 @@ /** - * Static functions for creating pagination + * Playback widget (play, pause , etc) */ (function(context, $) { diff --git a/web/app/assets/javascripts/profile.js b/web/app/assets/javascripts/profile.js index e0d281fe6..00273a333 100644 --- a/web/app/assets/javascripts/profile.js +++ b/web/app/assets/javascripts/profile.js @@ -375,12 +375,6 @@ $('.profile-nav a.active').removeClass('active'); $('.profile-nav a.#profile-social-link').addClass('active'); - /*if (isMusician()) { - $('.profile-social-left').show(); - } else { - $('.profile-social-left').hide(); - }*/ - bindSocial(); } diff --git a/web/app/assets/javascripts/recordingManager.js b/web/app/assets/javascripts/recordingManager.js new file mode 100644 index 000000000..54c8bc6e7 --- /dev/null +++ b/web/app/assets/javascripts/recordingManager.js @@ -0,0 +1,123 @@ +/** + * Recording Manager viewer + * Although multiple instances could be made, only one should be + */ +(function(context, $) { + + "use strict"; + + context.JK = context.JK || {}; + + context.JK.RecordingManager = function(){ + + var $parentElement = $('#recording-manager-viewer'); + + var logger = context.JK.logger; + if($parentElement.length == 0) { + logger.debug("no $parentElement specified in RecordingManager"); + } + + var $downloadCommand = $('#recording-manager-download', $parentElement); + var $downloadPercent = $('#recording-manager-download .percent', $parentElement); + var $uploadCommand = $('#recording-manager-upload', $parentElement); + var $uploadPercent = $('#recording-manager-upload .percent', $parentElement); + var $convertCommand = $('#recording-manager-convert', $parentElement); + var $convertPercent = $('#recording-manager-convert .percent', $parentElement); + + // keys come from backend + var lookup = { + SyncDownload: { command: $downloadCommand, percent: $downloadPercent }, + SyncUpload: { command: $uploadCommand, percent: $uploadPercent }, + SyncConvert: { command: $convertCommand, percent: $convertPercent } + } + + var $self = $(this); + + + function renderStartCommand($command) { + $command.css('visibility', 'visible'); + } + + function renderEndCommand($command) { + $command.css('visibility', 'hidden'); + } + + function renderPercentage($percent, value) { + $percent.text(Math.round(value * 100)); + } + + function onStartCommand(id, type) { + var command = lookup[type]; + if(!command) { return } + + var existingCommandId = command.command.data('command-id'); + + if(existingCommandId && existingCommandId != id) { + renderEndCommand(command.command); + } + + command.command.data('command-id', id); + renderStartCommand(command.command); + renderPercentage(command.percent, 0); + } + + function onStopCommand(id, type, success, reason, detail) { + var command = lookup[type]; + if(!command) { return } + + var existingCommandId = command.command.data('command-id'); + + if(!existingCommandId) { + command.command.data('command-id', id); + renderStartCommand(command.command); + } + else if(existingCommandId && existingCommandId != id) { + renderEndCommand(command.command); + command.command.data('command-id', id); + renderStartCommand(command.command); + } + + renderPercentage(command.percent, 1); + renderEndCommand(command.command); + command.command.data('command-id', null); + } + + function onCommandProgress(id, type, progress) { + var command = lookup[type]; + if(!command) { return } + + var existingCommandId = command.command.data('command-id'); + + if(!existingCommandId) { + command.command.data('command-id', id); + renderStartCommand(command.command); + } + else if(existingCommandId && existingCommandId != id) { + renderEndCommand(command.command); + command.command.data('command-id', id); + renderStartCommand(command.command); + } + + renderPercentage(command.percent, progress); + } + + function onCommandsChanged(id, type) { + + } + + context.JK.RecordingManagerCommandStart = onStartCommand; + context.JK.RecordingManagerCommandStop = onStopCommand; + context.JK.RecordingManagerCommandProgress = onCommandProgress; + context.JK.RecordingManagerCommandsChanged = onCommandsChanged; + + context.jamClient.RegisterRecordingManagerCallbacks( + "JK.RecordingManagerCommandStart", + "JK.RecordingManagerCommandProgress", + "JK.RecordingManagerCommandStop", + "JK.RecordingManagerCommandsChanged" + + ) + + return this; + } +})(window, jQuery); \ No newline at end of file diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js index 49264de6f..4245dbee8 100644 --- a/web/app/assets/javascripts/session.js +++ b/web/app/assets/javascripts/session.js @@ -590,7 +590,7 @@ var recordedTracks = sessionModel.recordedTracks(); - console.log("recorded tracks=%o local_media_mixers=%o", recordedTracks, localMediaMixers); + console.log("recorded tracks=%o local_media=%o", recordedTracks, localMediaMixers); if(recordedTracks && localMediaMixers.length == 0) { // if we are the creator, then rather than raise an error, tell the server the recording is over. diff --git a/web/app/assets/stylesheets/client/client.css b/web/app/assets/stylesheets/client/client.css index 4a66584e2..a852d46bf 100644 --- a/web/app/assets/stylesheets/client/client.css +++ b/web/app/assets/stylesheets/client/client.css @@ -18,6 +18,7 @@ *= require ./header #= require ./user_dropdown *= require ./footer + *= require ./recordingManager *= require ./screen_common *= require ./notify *= require ./dialog diff --git a/web/app/assets/stylesheets/client/clientUpdate.css.scss b/web/app/assets/stylesheets/client/clientUpdate.css.scss index 82f037af4..2b799b8da 100644 --- a/web/app/assets/stylesheets/client/clientUpdate.css.scss +++ b/web/app/assets/stylesheets/client/clientUpdate.css.scss @@ -1,34 +1,35 @@ #client_update { display:none; + + .progress-bar { + width:100%; + background-color:#000; + border: solid 1px #ED3618; + height:22px; + } + + #progress-bar { + width:0%; + } + + .progress-bar-progress { + background-color:#ED3618; + border:solid 1px #000; + height:20px; + display:block; + } + + h2 { + font-weight:bold; + font-size:x-large; + } + + #client-updater-updating #update-steps { + margin-top:20px; + } + + #client-updater-updating span.status { + color:white; + } } -.progress-bar { - width:100%; - background-color:#000; - border: solid 1px #ED3618; - height:22px; -} - -#progress-bar { - width:0%; -} - -.progress-bar-progress { - background-color:#ED3618; - border:solid 1px #000; - height:20px; - display:block; -} - -#client_update h2 { - font-weight:bold; - font-size:x-large; -} - -#client-updater-updating #update-steps { - margin-top:20px; -} - -#client-updater-updating span.status { - color:white; -} \ No newline at end of file diff --git a/web/app/assets/stylesheets/client/content.css.scss b/web/app/assets/stylesheets/client/content.css.scss index 38794f276..88550ab29 100644 --- a/web/app/assets/stylesheets/client/content.css.scss +++ b/web/app/assets/stylesheets/client/content.css.scss @@ -99,6 +99,55 @@ box-sizing: border-box; padding-top: 49px; } + + .profile-head { + position: absolute; + box-sizing: border-box; + width:100%; + } + .profile-body { + height:100%; + width:100%; + box-sizing: border-box; + padding-top: 157px; + > * { + box-sizing:border-box; + } + } + .profile-body-content { + height: inherit; + overflow:auto; + &.outer { + overflow:hidden; + } + &.padded { + padding:10px 25px; + } + } + + .profile-social-head { + position: absolute; + width:100%; + padding:0 25px; + line-height:25px; + box-sizing:border-box; + + +.profile-wrapper { + padding-top: 0; + } + } + .profile-social-body { + height:100%; + width:100%; + box-sizing:border-box; + padding-top:25px; + .profile-social-body-wrapper { + height:inherit; + } + .profile-social-content { + padding:0 25px; + } + } } .result-list-button-wrapper { diff --git a/web/app/assets/stylesheets/client/recordingManager.css.scss b/web/app/assets/stylesheets/client/recordingManager.css.scss new file mode 100644 index 000000000..8ed92305e --- /dev/null +++ b/web/app/assets/stylesheets/client/recordingManager.css.scss @@ -0,0 +1,42 @@ +#recording-manager-viewer { + + color: #CCCCCC; + font-size: 11px; + margin: 0 auto; + position: absolute; + text-align: center; + left: 25%; + width: 50%; + + .recording-manager-command { + box-sizing: border-box; + width:33%; + margin:5px 10px; + visibility: hidden; + + .percent { + margin-left:3px; + } + + .percent:after { + content:"%"; + } + + .progress-bar { + width:100%; + background-color:#000; + border: solid 1px #ED3618; + height:22px; + display:inline; + } + + .progress-bar-progress { + background-color:#ED3618; + border:solid 1px #000; + height:20px; + display:block; + width:0%; + display:inline; + } + } +} \ No newline at end of file diff --git a/web/app/assets/stylesheets/landing/footer.css.scss b/web/app/assets/stylesheets/landing/footer.css.scss index ad1bc8b7f..63fcbbaac 100644 --- a/web/app/assets/stylesheets/landing/footer.css.scss +++ b/web/app/assets/stylesheets/landing/footer.css.scss @@ -12,6 +12,10 @@ padding-top: 10px; margin: 30px 30px 0; border-top:solid 1px #444; + + #recording-manager-viewer { + display:none; + } } #copyright { diff --git a/web/app/assets/stylesheets/web/footer.css.scss b/web/app/assets/stylesheets/web/footer.css.scss index df599b11b..f29ff4261 100644 --- a/web/app/assets/stylesheets/web/footer.css.scss +++ b/web/app/assets/stylesheets/web/footer.css.scss @@ -10,6 +10,11 @@ #footer { padding-top: 10px; border-top:solid 1px #444; + + #recording-manager-viewer { + display:none; + } + } #copyright { diff --git a/web/app/assets/stylesheets/web/main.css.scss b/web/app/assets/stylesheets/web/main.css.scss index b9622093b..fb3b8f142 100644 --- a/web/app/assets/stylesheets/web/main.css.scss +++ b/web/app/assets/stylesheets/web/main.css.scss @@ -363,4 +363,4 @@ strong { fieldset.login-error .login-error-msg { display:block; } -} +} \ No newline at end of file diff --git a/web/app/views/clients/_footer.html.erb b/web/app/views/clients/_footer.html.erb index adb4012d0..6bd56c907 100644 --- a/web/app/views/clients/_footer.html.erb +++ b/web/app/views/clients/_footer.html.erb @@ -1,11 +1,12 @@
-
-
-
+ +

@@ -45,57 +44,83 @@
-
-
+ +
+
-
-

Location:


-


-

Stats:


-
-
-
-
-
-
-
-
-


-
+
+
+

Location:


+


+

Stats:


+
+
+
+
+
+
+
+


+
+
+
-
+
+
+
+
+

-
-
-
-
-
-

Friends

-
+
+
+
+

Friends

+
+
+

Following

+
+
+

Followers

+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
-
-

Following

-
+
+
+
+
-
-

Followers

-
-
-
-
-
-
-
+
-
diff --git a/web/app/views/clients/_recordingManager.html.erb b/web/app/views/clients/_recordingManager.html.erb new file mode 100644 index 000000000..6a1f7f2b4 --- /dev/null +++ b/web/app/views/clients/_recordingManager.html.erb @@ -0,0 +1,11 @@ + + + converting0 + + + uploading0 + + + downloading0 + + \ No newline at end of file diff --git a/web/app/views/clients/index.html.erb b/web/app/views/clients/index.html.erb index f23cc35bb..bbd434dbf 100644 --- a/web/app/views/clients/index.html.erb +++ b/web/app/views/clients/index.html.erb @@ -91,6 +91,8 @@ // Some things can't be initialized until we're connected. Put them here. function _initAfterConnect() { + var recordingManager = new JK.RecordingManager(); + var invitationDialog = new JK.InvitationDialog(JK.app); invitationDialog.initialize(); diff --git a/web/spec/features/recordings_spec.rb b/web/spec/features/recordings_spec.rb index c28ef056a..44c56716c 100644 --- a/web/spec/features/recordings_spec.rb +++ b/web/spec/features/recordings_spec.rb @@ -12,6 +12,7 @@ describe "Session Recordings", :js => true, :type => :feature, :capybara_feature let(:creator) { FactoryGirl.create(:user) } let(:joiner1) { FactoryGirl.create(:user) } + let(:joiner2) { FactoryGirl.create(:user) } let(:some_genre) { random_genre } before(:each) do @@ -21,18 +22,14 @@ describe "Session Recordings", :js => true, :type => :feature, :capybara_feature # creates a recording, and stops it, and confirms the 'Finished Recording' dialog shows for both it "creator start/stop" do start_recording_with(creator, [joiner1]) - in_client(creator) { stop_recording } - check_recording_finished_for([creator, joiner1]) end # confirms that anyone can start/stop a recording it "creator starts and other stops" do start_recording_with(creator, [joiner1]) - in_client(joiner1) { stop_recording } - check_recording_finished_for([creator, joiner1]) end @@ -64,8 +61,6 @@ describe "Session Recordings", :js => true, :type => :feature, :capybara_feature end it "creator starts/stops, with 3 total participants" do - joiner2 = FactoryGirl.create(:user) - start_recording_with(creator, [joiner1, joiner2]) in_client(creator) do @@ -76,7 +71,6 @@ describe "Session Recordings", :js => true, :type => :feature, :capybara_feature end it "creator starts with session leave to stop, with 3 total participants" do - joiner2 = FactoryGirl.create(:user) start_recording_with(creator, [joiner1, joiner2]) in_client(creator) do @@ -90,7 +84,6 @@ describe "Session Recordings", :js => true, :type => :feature, :capybara_feature # confirms that if someone leaves 'ugly' (without calling 'Leave' REST API), that the recording is junked with 3 participants it "creator starts and then abruptly leave with 3 participants" do - joiner2 = FactoryGirl.create(:user) start_recording_with(creator, [joiner1, joiner2]) in_client(creator) do @@ -160,12 +153,12 @@ describe "Session Recordings", :js => true, :type => :feature, :capybara_feature claim_recording(name, desc) music_session = MusicSession.first() recording = music_session.recordings.first() - claimed_recording = ClaimedRecording.find_by_user_id(user.id) - claimed_recording.name.should == name - claimed_recording.description.should == desc - claimed_recording.is_public.should be_true - claimed_recording.is_downloadable.should be_true - claimed_recording.genre = music_session.genres[0] + claimed_recording = recording.claimed_recordings.where(:user_id => user.id).first + expect(claimed_recording.name).to eq(name) + expect(claimed_recording.description).to eq(desc) + expect(claimed_recording.is_public).to be_true + expect(claimed_recording.is_downloadable).to be_true + expect(claimed_recording.genre).to eq(music_session.genres[0]) end end end @@ -189,12 +182,12 @@ describe "Session Recordings", :js => true, :type => :feature, :capybara_feature claim_recording("my recording", '') music_session = MusicSession.first() recording = music_session.recordings.first() - claimed_recording = ClaimedRecording.find_by_user_id(user.id) - claimed_recording.name.should == "my recording" - claimed_recording.description.should == '' - claimed_recording.is_public.should be_true - claimed_recording.is_downloadable.should be_true - claimed_recording.genre = music_session.genres[0] + claimed_recording = recording.claimed_recordings.where(:user_id => user.id).first + expect(claimed_recording.name).to eq("my recording") + expect(claimed_recording.description).to eq('') + expect(claimed_recording.is_public).to be_true + expect(claimed_recording.is_downloadable).to be_true + expect(claimed_recording.genre).to eq(music_session.genres[0]) end end end diff --git a/web/spec/support/utilities.rb b/web/spec/support/utilities.rb index a4578efa4..4074074a7 100644 --- a/web/spec/support/utilities.rb +++ b/web/spec/support/utilities.rb @@ -37,8 +37,7 @@ def wipe_s3_test_bucket :secret_access_key => Rails.application.config.aws_secret_access_key) test_bucket = s3.buckets[JAMKAZAM_TESTING_BUCKET] if test_bucket.name == JAMKAZAM_TESTING_BUCKET - puts "Web - Pretending to delete all contents of #{test_bucket.name}" - #test_bucket.delete_all + #test_bucket.clear! end end