diff --git a/admin/app/controllers/checks_controller.rb b/admin/app/controllers/checks_controller.rb
new file mode 100644
index 000000000..52330c2aa
--- /dev/null
+++ b/admin/app/controllers/checks_controller.rb
@@ -0,0 +1,19 @@
+class ChecksController < ApplicationController
+
+ #respond_to :json
+
+ # create or update a client_artifact row
+ def check_latency_tester
+
+ latency_tester_name = params[:name]
+
+ exists = Connection.where(client_type: Connection::TYPE_LATENCY_TESTER).where(client_id: latency_tester_name).first
+
+ if exists
+ render :text => "", :status => :ok
+ else
+ render :text => "", :status => 404
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/admin/config/routes.rb b/admin/config/routes.rb
index 05aed06bc..bae57c044 100644
--- a/admin/config/routes.rb
+++ b/admin/config/routes.rb
@@ -32,6 +32,7 @@ JamAdmin::Application.routes.draw do
match '/api/artifacts' => 'artifacts#update_artifacts', :via => :post
match '/api/mix/:id/enqueue' => 'admin/mixes#mix_again', :via => :post
+ match '/api/checks/latency_tester' => 'checks#check_latency_tester', :via => :get
mount Resque::Server.new, :at => "/resque"
diff --git a/db/manifest b/db/manifest
index fd9bab56b..fc5d059bc 100755
--- a/db/manifest
+++ b/db/manifest
@@ -256,4 +256,6 @@ remove_bpm_from_jamtracks.sql
alter_type_columns.sql
user_presences_rename.sql
add_genre_type.sql
+add_description_to_perf_samples.sql
+widen_user_authorization_token.sql
musician_search.sql
diff --git a/db/up/add_description_to_perf_samples.sql b/db/up/add_description_to_perf_samples.sql
new file mode 100644
index 000000000..2c1ee462e
--- /dev/null
+++ b/db/up/add_description_to_perf_samples.sql
@@ -0,0 +1 @@
+alter table performance_samples add column description varchar(256) NULL;
\ No newline at end of file
diff --git a/db/up/recorded_jam_track_tracks.sql b/db/up/recorded_jam_track_tracks.sql
new file mode 100644
index 000000000..246b76425
--- /dev/null
+++ b/db/up/recorded_jam_track_tracks.sql
@@ -0,0 +1,15 @@
+ALTER TABLE recordings ADD COLUMN jam_track_id VARCHAR(64) REFERENCES jam_tracks(id);
+ALTER TABLE recordings ADD COLUMN jam_track_initiator_id VARCHAR(64) REFERENCES users(id);
+
+CREATE TABLE recorded_jam_track_tracks (
+ id BIGINT PRIMARY KEY,
+ user_id VARCHAR(64) REFERENCES users(id) ON DELETE CASCADE,
+ jam_track_track_id VARCHAR(64),
+ recording_id VARCHAR(64) NOT NULL,
+ discard BOOLEAN,
+ timeline JSON,
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+ALTER TABLE recorded_jam_tracks ALTER COLUMN id SET DEFAULT nextval('tracks_next_tracker_seq');
\ No newline at end of file
diff --git a/db/up/widen_user_authorization_token.sql b/db/up/widen_user_authorization_token.sql
new file mode 100644
index 000000000..070f67b83
--- /dev/null
+++ b/db/up/widen_user_authorization_token.sql
@@ -0,0 +1 @@
+alter table user_authorizations ALTER COLUMN token TYPE character varying(2000);
\ No newline at end of file
diff --git a/web/README.md b/web/README.md
index b32f3ab99..f2dccf0a1 100644
--- a/web/README.md
+++ b/web/README.md
@@ -1,10 +1,4 @@
Jasmine Javascript Unit Tests
=============================
-1. Ensure you have the jasmine Gem installed;
-$ bundle
-
-2. Start the jasmine server (defaults to :8888)
-$ rake jasmine
-
-Open browser to localhost:8888
+Open browser to localhost:3000/teaspoon
diff --git a/web/app/assets/javascripts/profile.js b/web/app/assets/javascripts/profile.js
index 7ce15f46e..20efadbf6 100644
--- a/web/app/assets/javascripts/profile.js
+++ b/web/app/assets/javascripts/profile.js
@@ -27,10 +27,21 @@
var $studioCount = $screen.find('#studio-count');
// performance samples
- var $noSamples = $screen.find('no-samples');
+ var $noSamples = $screen.find('#no-samples');
+ var $jamkazamSamples = $screen.find('#jamkazam-samples');
+ var $soundCloudSamples = $screen.find('#soundcloud-samples');
+ var $youTubeSamples = $screen.find('#youtube-samples');
// online presence
- var $noOnlinePresence = $screen.find('no-online-presence');
+ var $noOnlinePresence = $screen.find('#no-online-presence');
+ var $userWebsite = $screen.find('#user-website');
+ var $soundCloudPresence = $screen.find('#soundcloud-presence');
+ var $reverbNationPresence = $screen.find('#reverbnation-presence');
+ var $bandCampPresence = $screen.find('#bandcamp-presence');
+ var $fandalismPresence = $screen.find('#fandalism-presence');
+ var $soundCloudPresence = $screen.find('#youtube-presence');
+ var $soundCloudPresence = $screen.find('#facebook-presence');
+ var $youTubePresence = $screen.find('#twitter-presence');
// current interests
var $noInterests = $screen.find('#no-interests');
@@ -43,10 +54,10 @@
var $cowritingSection = $screen.find('#cowriting');
var $cowritingDetails = $screen.find('#cowriting-details');
- var $traditionalBandSection = $screen.find("#traditional-band");
+ var $traditionalBandSection = $screen.find('#traditional-band');
var $traditionalBandDetails = $screen.find('#traditional-band-details');
- var $virtualBandSection = $screen.find("#virtual-band");
+ var $virtualBandSection = $screen.find('#virtual-band');
var $virtualBandDetails = $screen.find('#virtual-band-details');
// tabs
@@ -483,6 +494,23 @@
}
else {
$noSamples.hide();
+
+ // show samples section
+ var jamkazamSamples = profileUtils.jamkazamSamples(user.performance_samples);
+ var soundCloudSamples = profileUtils.soundCloudSamples(user.performance_samples);
+ var youTubeSamples = profileUtils.youTubeSamples(user.performance_samples);
+
+ $.each(jamkazamSamples, function(index, sample) {
+ $jamkazamSamples.append("" + sample.claimed_recording.name + "");
+ });
+
+ $.each(soundCloudSamples, function(index, sample) {
+ $soundCloudSamples.append("" + sample.service_id + "");
+ });
+
+ $.each(youTubeSamples, function(index, sample) {
+ $youTubeSamples.append("" + sample.service_id + "");
+ });
}
// online presences
@@ -491,7 +519,15 @@
$noOnlinePresence.show();
}
else {
- $noOnlinePresence.hide();
+ $noOnlinePresence.hide();
+
+ if (user.website) {
+ $userWebsite.append("");
+ }
+
+ $.each(onlinePresences, function(index, presence) {
+
+ });
}
// current interests
diff --git a/web/app/assets/javascripts/profile_utils.js b/web/app/assets/javascripts/profile_utils.js
index 8c1eba1a1..32b5ce542 100644
--- a/web/app/assets/javascripts/profile_utils.js
+++ b/web/app/assets/javascripts/profile_utils.js
@@ -18,9 +18,21 @@
var COWRITING_GENRE_TYPE = 'cowriting';
// performance samples
- var JAMKAZAM = 'jamkazam';
- var SOUNDCLOUD = 'soundcloud';
- var YOUTUBE = 'youtube';
+ var SAMPLE_TYPES = {
+ JAMKAZAM: {description: "jamkazam"},
+ SOUNDCLOUD: {description: "soundcloud"},
+ YOUTUBE: {description: "youtube"}
+ };
+
+ var ONLINE_PRESENCE_TYPES = {
+ SOUNDCLOUD: {description: "soundcloud"},
+ REVERBNATION: {description: "reverbnation"},
+ BANDCAMP: {description: "bandcamp"},
+ FANDALISM: {description: "fandalism"},
+ YOUTUBE: {description: "youtube"},
+ FACEBOOK: {description: "facebook"},
+ TWITTER: {description: "twitter"}
+ };
var USER_TYPE = 'JamRuby::User';
@@ -148,7 +160,7 @@
profileUtils.jamkazamSamples = function(samples) {
var matches = $.grep(samples, function(s) {
- return s.service_type === JAMKAZAM;
+ return s.service_type === SAMPLE_TYPES.JAMKAZAM.description;
});
return matches;
@@ -156,7 +168,7 @@
profileUtils.soundCloudSamples = function(samples) {
var matches = $.grep(samples, function(s) {
- return s.service_type === SOUNDCLOUD;
+ return s.service_type === SAMPLE_TYPES.SOUNDCLOUD.description;
});
return matches;
@@ -164,7 +176,63 @@
profileUtils.youTubeSamples = function(samples) {
var matches = $.grep(samples, function(s) {
- return s.service_type === YOUTUBE;
+ return s.service_type === SAMPLE_TYPES.YOUTUBE.description;
+ });
+
+ return matches;
+ }
+
+ profileUtils.soundCloudPresences = function(presences) {
+ var matches = $.grep(presences, function(p) {
+ return p.service_type === ONLINE_PRESENCE_TYPES.SOUNDCLOUD.description;
+ });
+
+ return matches;
+ }
+
+ profileUtils.reverbNationPresences = function(presences) {
+ var matches = $.grep(presences, function(p) {
+ return p.service_type === ONLINE_PRESENCE_TYPES.REVERBNATION.description;
+ });
+
+ return matches;
+ }
+
+ profileUtils.bandCampPresences = function(presences) {
+ var matches = $.grep(presences, function(p) {
+ return p.service_type === ONLINE_PRESENCE_TYPES.BANDCAMP.description;
+ });
+
+ return matches;
+ }
+
+ profileUtils.fandalismPresences = function(presences) {
+ var matches = $.grep(presences, function(p) {
+ return p.service_type === ONLINE_PRESENCE_TYPES.FANDALISM.description;
+ });
+
+ return matches;
+ }
+
+ profileUtils.youTubePresences = function(presences) {
+ var matches = $.grep(presences, function(p) {
+ return p.service_type === ONLINE_PRESENCE_TYPES.YOUTUBE.description;
+ });
+
+ return matches;
+ }
+
+ profileUtils.facebookPresences = function(presences) {
+ var matches = $.grep(presences, function(p) {
+ return p.service_type === ONLINE_PRESENCE_TYPES.FACEBOOK.description;
+ });
+
+ return matches;
+ }
+
+ profileUtils.twitterPresences = function(presences) {
+ var matches = $.grep(presences, function(p) {
+ return s.service_type === ONLINE_PRESENCE_TYPES.TWITTER.description;
});
return matches;
diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js
index d91ebf0d5..b47946641 100644
--- a/web/app/assets/javascripts/session.js
+++ b/web/app/assets/javascripts/session.js
@@ -890,8 +890,11 @@
var mediaType = mixer.media_type;
var groupId = mixer.group_id;
- // mediaType == null is for backwards compat with older clients. Can be removed soon
- if(mediaType == null || mediaType == "" || mediaType == 'RecordingTrack') {
+ if(mediaType == 'MetronomeTrack' || groupId==ChannelGroupIds.MetronomeGroup) {
+ // Metronomes come across with a blank media type, so check group_id:
+ metronomeTrackMixers.push(mixer);
+ }
+ else if(mediaType == null || mediaType == "" || mediaType == 'RecordingTrack') {
// additional check; if we can match an id in backing tracks or recorded backing track,
// we need to remove it from the recorded track set, but move it to the backing track set
@@ -922,9 +925,6 @@
} else if(mediaType == 'PeerMediaTrack' || mediaType == 'BackingTrack') {
// BackingTrack
backingTrackMixers.push(mixer);
- } else if(mediaType == 'MetronomeTrack' || groupId==ChannelGroupIds.MetronomeGroup) {
- // Metronomes come across with a blank media type, so check group_id:
- metronomeTrackMixers.push(mixer);
} else if(mediaType == 'JamTrack') {
jamTrackMixers.push(mixer);
mixer.group_id == ChannelGroupIds.MediaTrackGroup;
@@ -1027,7 +1027,12 @@
if(isOpener) {
var oppositeMixer = getMixerByResourceId(mixer.rid, MIX_MODES.PERSONAL);
+ var mixerId = mixer.id + "," + oppositeMixer.uniqueId
}
+ else {
+ var mixerId = mixer.id;
+ }
+
var shortFilename = context.JK.getNameOfFile(backingTrack.filename);
if(!sessionModel.isPlayingRecording()) {
@@ -1067,7 +1072,7 @@
trackData.gainPercent = gainPercent;
trackData.muteClass = muteClass;
- trackData.mixerId = mixer.id + "," + oppositeMixer.uniqueId; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode)
+ trackData.mixerId = mixerId; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode)
trackData.vuMixerId = mixer.id; // the master mixer controls the VUs for recordings (no personal controls in either master or personal mode)
trackData.muteMixerId = mixer.id; // the master mixer controls the mute for recordings (no personal controls in either master or personal mode)
trackData.mediaTrackOpener = isOpener;
@@ -1132,7 +1137,12 @@
if(isOpener) {
var oppositeMixer = getMixerByResourceId(mixer.rid, MIX_MODES.PERSONAL);
+ var mixerId = mixer.id + "," + oppositeMixer.uniqueId
}
+ else {
+ var mixerId = mixer.id;
+ }
+
// Default trackData to participant + no Mixer state.
var trackData = {
trackId: oneOfTheTracks.id,
@@ -1156,7 +1166,7 @@
}
trackData.gainPercent = gainPercent;
trackData.muteClass = muteClass;
- trackData.mixerId = mixer.id + "," + oppositeMixer.uniqueId; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode)
+ trackData.mixerId = mixerId; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode)
trackData.vuMixerId = mixer.id; // the master mixer controls the VUs for recordings (no personal controls in either master or personal mode)
trackData.muteMixerId = mixer.id; // the master mixer controls the mute for recordings (no personal controls in either master or personal mode)
trackData.mediaTrackOpener = isOpener;
@@ -1235,8 +1245,13 @@
if(isOpener) {
var oppositeMixer = getMixerByResourceId(mixer.rid, MIX_MODES.PERSONAL);
+ var mixerId = mixer.id + "," + oppositeMixer.uniqueId
}
-
+ else {
+ var mixerId = mixer.id;
+ }
+
+
// Default trackData to participant + no Mixer state.
var trackData = {
trackId: "MS" + oneOfTheTracks.id,
@@ -1261,7 +1276,7 @@
}
trackData.gainPercent = gainPercent;
trackData.muteClass = muteClass;
- trackData.mixerId = mixer.id + "," + oppositeMixer.uniqueId; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode)
+ trackData.mixerId = mixerId; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode)
trackData.vuMixerId = mixer.id; // the master mixer controls the VUs for recordings (no personal controls in either master or personal mode)
trackData.muteMixerId = mixer.id; // the master mixer controls the mute for recordings (no personal controls in either master or personal mode)
trackData.mediaTrackOpener = isOpener;
@@ -1338,6 +1353,10 @@
if(isOpener) {
var oppositeMixer = getMixerByResourceId(mixer.rid, MIX_MODES.PERSONAL);
+ var mixerId = mixer.id + "," + oppositeMixer.uniqueId
+ }
+ else {
+ var mixerId = mixer.id;
}
// Default trackData to participant + no Mixer state.
@@ -1363,7 +1382,7 @@
}
trackData.gainPercent = gainPercent;
trackData.muteClass = muteClass;
- trackData.mixerId = mixer.id + "," + oppositeMixer.uniqueId; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode)
+ trackData.mixerId = mixerId; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode)
trackData.vuMixerId = mixer.id; // the master mixer controls the VUs for recordings (no personal controls in either master or personal mode)
trackData.muteMixerId = mixer.id; // the master mixer controls the mute for recordings (no personal controls in either master or personal mode)
trackData.mediaControlsDisabled = !isOpener;
@@ -1961,11 +1980,22 @@
rest.openBackingTrack({id: context.JK.CurrentSessionModel.id(), backing_track_path: result.file})
.done(function(response) {
var openResult = context.jamClient.SessionOpenBackingTrackFile(result.file, false);
- //context.JK.CurrentSessionModel.refreshCurrentSession(true);
- sessionModel.setBackingTrack(result.file);
+
+ if(openResult) {
+ sessionModel.setBackingTrack(result.file);
+ }
+ else {
+ app.notify({
+ "title": "Couldn't Open Backing Track",
+ "text": "Is the file a valid audio file?",
+ "icon_url": "/assets/content/icon_alert_big.png"
+ });
+ closeBackingTrack();
+ }
+
})
.fail(function(jqXHR) {
- app.notifyServerError(jqXHR, "Unable to Open BackingTrack For Playback");
+ app.notifyServerError(jqXHR, "Unable to Open Backing Track For Playback");
})
}
else {
@@ -2110,7 +2140,11 @@
context.trackVolumeObject.name = mixer.name;
context.trackVolumeObject.record = mixer.record;
context.trackVolumeObject.volL = mixer.volume_left;
- context.trackVolumeObject.volR = mixer.volume_right;
+
+ // today we treat all tracks as mono, but this is required to make a stereo track happy
+ //context.trackVolumeObject.volR = mixer.volume_right;
+ context.trackVolumeObject.volR = mixer.volume_left;
+
context.trackVolumeObject.loop = mixer.loop;
// trackVolumeObject doesn't have a place for range min/max
currentMixerRangeMin = mixer.range_low;
@@ -2424,8 +2458,6 @@
rest.openMetronome({id: sessionModel.id()})
.done(function() {
context.jamClient.SessionOpenMetronome(120, "Click", 1, 0)
- context.JK.CurrentSessionModel.refreshCurrentSession(true)
- context.JK.CurrentSessionModel.refreshCurrentSession(true)
})
.fail(function(jqXHR) {
logger.debug(jqXHR, jqXHR)
@@ -2487,8 +2519,8 @@
})
.fail(function(jqXHR) {
app.notify({
- "title": "Couldn't Close BackingTrack",
- "text": "Couldn't inform the server to close BackingTrack. msg=" + jqXHR.responseText,
+ "title": "Couldn't Close Backing Track",
+ "text": "Couldn't inform the server to close Backing Track. msg=" + jqXHR.responseText,
"icon_url": "/assets/content/icon_alert_big.png"
});
});
diff --git a/web/app/views/api_users/profile_show.rabl b/web/app/views/api_users/profile_show.rabl
index c88dfa048..0ad7585f1 100644
--- a/web/app/views/api_users/profile_show.rabl
+++ b/web/app/views/api_users/profile_show.rabl
@@ -8,7 +8,7 @@ child :online_presences => :online_presences do
end
child :performance_samples => :performance_samples do
- attributes :id, :url, :service_type, :claimed_recording_id, :service_id
+ attributes :id, :url, :service_type, :claimed_recording_id, :service_id, :description
child :claimed_recording => :claimed_recording do
attributes :name
diff --git a/web/app/views/clients/_profile.html.erb b/web/app/views/clients/_profile.html.erb
index 4224184b0..e95e22c45 100644
--- a/web/app/views/clients/_profile.html.erb
+++ b/web/app/views/clients/_profile.html.erb
@@ -121,6 +121,15 @@