From 4d7712093a2487a17e1ee112d04797d67d8bdef1 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Sat, 10 Jun 2017 15:34:08 -0500 Subject: [PATCH] working on livestream --- ruby/lib/jam_ruby/models/broadcast.rb | 19 +- ruby/lib/jam_ruby/models/music_session.rb | 111 +- web/app/assets/javascripts/fakeJamClient.js | 1 - web/app/assets/javascripts/jam_rest.js | 5991 +++++++++-------- .../assets/javascripts/react-components.js | 1 + .../PopupVideoLiveStream.js.jsx.coffee | 187 + .../actions/VideoActions.js.coffee | 1 + .../actions/VideoLiveStreamActions.js.coffee | 9 + .../stores/CallbackStore.js.coffee | 4 +- .../stores/VideoLiveStreamStore.js.coffee | 265 + .../stores/VideoStore.js.coffee | 2 + .../dialogs/liveStreamingDialog.scss | 57 + .../minimal/video_live_stream.scss | 58 + .../stylesheets/minimal/video_stream.scss | 6 +- .../api_music_sessions_controller.rb | 44 +- web/app/controllers/popups_controller.rb | 6 + .../api_music_sessions/create_livestream.rabl | 3 + .../api_music_sessions/get_livestream.rabl | 3 + .../api_music_sessions/livestream_show.rabl | 3 + .../livestream_transition.rabl | 3 + .../dialogs/_liveStreamingDialog.html.slim | 2 + web/app/views/popups/video_stream.html.slim | 2 +- web/config/routes.rb | 4 + web/lib/google_client.rb | 58 +- web/lib/tasks/google.rake | 72 + web/lib/user_manager.rb | 4 + 26 files changed, 3912 insertions(+), 3004 deletions(-) create mode 100644 web/app/assets/javascripts/react-components/PopupVideoLiveStream.js.jsx.coffee create mode 100644 web/app/assets/javascripts/react-components/actions/VideoLiveStreamActions.js.coffee create mode 100644 web/app/assets/javascripts/react-components/stores/VideoLiveStreamStore.js.coffee create mode 100644 web/app/assets/stylesheets/dialogs/liveStreamingDialog.scss create mode 100644 web/app/assets/stylesheets/minimal/video_live_stream.scss create mode 100644 web/app/views/api_music_sessions/create_livestream.rabl create mode 100644 web/app/views/api_music_sessions/get_livestream.rabl create mode 100644 web/app/views/api_music_sessions/livestream_show.rabl create mode 100644 web/app/views/api_music_sessions/livestream_transition.rabl create mode 100644 web/app/views/dialogs/_liveStreamingDialog.html.slim diff --git a/ruby/lib/jam_ruby/models/broadcast.rb b/ruby/lib/jam_ruby/models/broadcast.rb index 68ac588ac..353650c8b 100644 --- a/ruby/lib/jam_ruby/models/broadcast.rb +++ b/ruby/lib/jam_ruby/models/broadcast.rb @@ -4,15 +4,30 @@ module JamRuby @@log = Logging.logger[Broadcast] - STATUS_COMPLETED = 'completed' + STATUS_COMPLETED = 'complete' STATUS_ABANDONED = 'abandoned' STATUS_REVOKED = 'revoked' + STATUS_DELETED = 'deleted' - DONE_STATUSES = [STATUS_COMPLETED, STATUS_ABANDONED, STATUS_REVOKED] + DONE_STATUSES = [STATUS_ABANDONED, STATUS_REVOKED, STATUS_DELETED, STATUS_COMPLETED] belongs_to :music_session, :class_name => 'JamRuby::MusicSsession' def self.current_broadcast(music_session) Broadcast.where(music_session_id: music_session.id).where('broadcast_status not in (?)', Broadcast::DONE_STATUSES).first end + + def self.unlink_broadcast(music_session) + broadcast = current_broadcast(music_session) + if broadcast + broadcast.broadcast_status = STATUS_DELETED + broadcast.save + end + end + + # data should be JSON hash from google API + def update_broadcast_data(data) + self.broadcast_status = data["status"]["lifeCycleStatus"] + self.broadcast_data = data.to_json + end end end diff --git a/ruby/lib/jam_ruby/models/music_session.rb b/ruby/lib/jam_ruby/models/music_session.rb index d583a1b46..a33a2b57e 100644 --- a/ruby/lib/jam_ruby/models/music_session.rb +++ b/ruby/lib/jam_ruby/models/music_session.rb @@ -83,31 +83,40 @@ module JamRuby Broadcast.current_broadcast(self) end - def create_broadcast(google_client, user, broadcast_options) + def unlink_broadcast + Broadcast.unlink_broadcast(self) + end + + def create_broadcast(user, broadcast_options, google_client = GoogleClient.new) broadcast = current_broadcast if broadcast.nil? - broadcast = create_youtube_broadcast(google_client, user, broadcast_options) + broadcast = create_youtube_broadcast(user, broadcast_options, google_client) else - refresh_youtube_broadcast(google_client, user, broadcast) + result = refresh_youtube_broadcast(user, broadcast, broadcast_options, google_client) # check against Youtube the real state of broadcast, to see if we need a new one? + + if result.nil? + unlink_broadcast # user probably deleted it, or marked it complete. + broadcast = create_youtube_broadcast(user, broadcast_options, google_client) + end end broadcast end - def create_stream(google_client, user, broadcast_options) + def create_stream(user, broadcast_options, google_client = GoogleClient.new) - broadcast = create_broadcast(google_client, user, broadcast_options) + broadcast = create_broadcast(user, broadcast_options, google_client) stream = current_stream(broadcast) if stream.nil? - create_youtube_stream(google_client, user, broadcast, broadcast_options) - bind_broadcast(google_client, user, broadcast) + create_youtube_stream(user, broadcast, broadcast_options, google_client) + bind_broadcast(user, broadcast, google_client) else - bind_broadcast(google_client, user, broadcast) + bind_broadcast(user, broadcast, google_client) end end @@ -115,14 +124,66 @@ module JamRuby broadcast.stream_id end - def refresh_youtube_broadcast(google_client, user, broadcast) - broadcast_data = google_client.get_broadcast(user, broadcast.broadcast_id) - broadcast.broadcast_status = broadcast_data["status"]["lifeCycleStatus"] - broadcast.broadcast_data = broadcast_data.to_json + def refresh_youtube_broadcast(user, broadcast, broadcast_data = nil, google_client = GoogleClient.new) + if broadcast_data.nil? + broadcast_data = google_client.get_broadcast(user, broadcast.broadcast_id) + end + + if broadcast_data + broadcast.update_broadcast_data(broadcast_data) + broadcast.save + true + else + # this path makes sense if the user deleted the video on the server, but we do not yet know it + nil + end + end + def get_livestream(user, google_client = GoogleClient.new) + broadcast = current_broadcast + + if broadcast.nil? + nil + else + stream_id = current_stream(broadcast) + + if stream_id.nil? + nil + else + return google_client.get_livestream(user, stream_id) + end + end + end + + def get_broadcast(user, google_client = UserManager.new.get_google_client) + broadcast = current_broadcast + + if broadcast.nil? + nil + else + broadcast_data = google_client.get_broadcast(user, broadcast.broadcast_id) + broadcast.update_broadcast_data(broadcast_data) + broadcast.save + broadcast + end + end + + def set_livestream_live(user, google_client = GoogleClient.new) + livestream = get_livestream(user, google_client) + + if livestream + if livestream["status"]["streamStatus"] == "active" + transition_broadcast(user, broadcast, 'live', google_client) + end + else + end + + end + + # https://developers.google.com/youtube/v3/live/docs/liveStreams#resource - def create_youtube_stream(google_client, user, broadcast, broadcast_options) + def create_youtube_stream(user, broadcast, broadcast_options, google_client = GoogleClient.new) # https://developers.google.com/youtube/v3/live/docs/liveStreams/insert # required @@ -133,7 +194,7 @@ module JamRuby stream_options = {} stream_options[:snippet] ||= {} stream_options[:snippet][:title] ||= name - stream_options[:snippet][:isDefaultStream] = false + stream_options[:snippet][:isDefaultStream] ||= false #broadcast_options[:snippet][:scheduledEndTime] = end_time.utc.iso8601 stream_options[:cdn] ||= {} @@ -142,7 +203,9 @@ module JamRuby stream_options[:cdn][:ingestionType] ||= 'rtmp' stream_options[:contentDetails] ||= {} - stream_options[:contentDetails][:isReusable] = false + stream_options[:contentDetails][:isReusable] ||= false + stream_options[:contentDetails][:monitorStream] ||= {} + stream_options[:contentDetails][:monitorStream][:enableMonitorStream] ||= false stream_options = google_client.create_stream(user, stream_options) @@ -155,7 +218,7 @@ module JamRuby broadcast end - def create_youtube_broadcast(google_client, user, broadcast_options) + def create_youtube_broadcast(user, broadcast_options, google_client = GoogleClient.new) start_time, end_time = youtube_times broadcast_options ||= {} @@ -181,16 +244,24 @@ module JamRuby broadcast.music_session_id = self.id broadcast.user_id = user.id broadcast.broadcast_id = broadcast_data["id"] - broadcast.broadcast_status = broadcast_data["status"]["lifeCycleStatus"] - broadcast.broadcast_data = broadcast_data.to_json + broadcast.update_broadcast_data(broadcast_data) broadcast.save! broadcast end - def bind_broadcast(google_client, user, broadcast) + def bind_broadcast(user, broadcast, google_client = GoogleClient.new) bind_data = google_client.bind_broadcast(user, broadcast.broadcast_id, broadcast.stream_id) - broadcast.broadcast_data = bind_data.to_json + broadcast.update_broadcast_data(bind_data) + broadcast.save! + broadcast + end + + # broadcastStatus one of complete, live, testing + def transition_broadcast(user, broadcast, broadcastStatus, google_client = GoogleClient.new) + + bind_data = google_client.transition_broadcast(user, broadcast.broadcast_id, broadcastStatus) + broadcast.update_broadcast_data(bind_data) broadcast.save! broadcast end diff --git a/web/app/assets/javascripts/fakeJamClient.js b/web/app/assets/javascripts/fakeJamClient.js index b40f20262..7e2da352e 100644 --- a/web/app/assets/javascripts/fakeJamClient.js +++ b/web/app/assets/javascripts/fakeJamClient.js @@ -1752,7 +1752,6 @@ this.isSessVideoShared = isSessVideoShared; this.SessStopVideoSharing = SessStopVideoSharing; this.SessStartVideoSharing = SessStartVideoSharing; - this.getOpenVideoSources = getOpenVideoSources; // Clipboard this.SaveToClipboard = SaveToClipboard; diff --git a/web/app/assets/javascripts/jam_rest.js b/web/app/assets/javascripts/jam_rest.js index a206635b9..24d1bb88f 100644 --- a/web/app/assets/javascripts/jam_rest.js +++ b/web/app/assets/javascripts/jam_rest.js @@ -1,3005 +1,3046 @@ -(function(context,$) { +(function (context, $) { - /** - * Javascript wrappers for the REST API + /** + * Javascript wrappers for the REST API + */ + + "use strict"; + + context.JK = context.JK || {}; + context.JK.Rest = function () { + + var self = this; + var logger = context.JK.logger; + + function createJoinRequest(joinRequest) { + return $.ajax({ + type: "POST", + dataType: "json", + url: '/api/join_requests', + contentType: 'application/json', + processData: false, + data: JSON.stringify(joinRequest) + }); + } + + function updateJoinRequest(joinRequestId, isApproved) { + return $.ajax({ + type: "PUT", + dataType: "json", + url: '/api/join_requests/' + joinRequestId, + contentType: 'application/json', + processData: false, + data: JSON.stringify({"approved": isApproved}) + }); + } + + function legacyCreateSession(options) { + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/sessions/legacy", + processData: false, + data: JSON.stringify(options) + }); + } + + function createScheduledSession(options) { + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/sessions", + processData: false, + data: JSON.stringify(options) + }); + } + + function getBroadcastNotification(options) { + var userId = getId(options); + return $.ajax({ + type: "GET", + url: "/api/users/" + userId + "/broadcast_notification" + }); + } + + function quietBroadcastNotification(options) { + var userId = getId(options); + var broadcast_id = options.broadcast_id; + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/users/" + userId + "/broadcast_notification/" + broadcast_id + '/quiet', + data: JSON.stringify({}), + }); + } + + function uploadMusicNotations(formData) { + return $.ajax({ + type: "POST", + processData: false, + contentType: false, + dataType: "json", + cache: false, + url: "/api/music_notations", + data: formData + }); + } + + function getMusicNotation(query) { + return $.ajax({ + type: "GET", + url: "/api/music_notations/" + query + }); + } + + + function deleteMusicNotation(options) { + return $.ajax({ + type: "DELETE", + url: "/api/music_notations/" + options.id + }); + } + + function legacyJoinSession(options) { + var sessionId = options["session_id"]; + delete options["session_id"]; + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/sessions/" + sessionId + "/participants/legacy", + data: JSON.stringify(options), + processData: false + }); + } + + function joinSession(options) { + var sessionId = options["session_id"]; + delete options["session_id"]; + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/sessions/" + sessionId + "/participants", + data: JSON.stringify(options), + processData: false + }); + } + + function cancelSession(options) { + var sessionId = options["session_id"]; + delete options["session_id"]; + + return $.ajax({ + type: "DELETE", + dataType: "JSON", + contentType: 'application/json', + url: "/api/sessions/" + sessionId, + data: JSON.stringify(options), + processData: false + }); + } + + function findActiveSessions(query) { + return $.ajax({ + type: "GET", + url: "/api/sessions/active?" + $.param(query) + }); + } + + function findInactiveSessions(query) { + return $.ajax({ + type: "GET", + url: "/api/sessions/inactive?" + $.param(query) + }); + } + + function findScheduledSessions(query) { + return $.ajax({ + type: "GET", + url: "/api/sessions/scheduled?" + $.param(query) + }); + } + + function findScheduledRsvpSessions(query) { + return $.ajax({ + type: "GET", + url: "/api/sessions/scheduled_rsvp?" + $.param(query) + }); + } + + function updateSession(id, newSession) { + return $.ajax({ + url: '/api/sessions/' + id, + type: "PUT", + data: newSession, + dataType: 'json' + }); + } + + function updateScheduledSession(id, newSession) { + return $.ajax({ + url: '/api/sessions/' + id, + type: "POST", + data: newSession, + dataType: 'json' + }); + } + + function getSessionHistory(id, includePending) { + var includeFlag = 'false'; + if (includePending) { + includeFlag = 'true'; + } + + return $.ajax({ + type: "GET", + dataType: "json", + url: '/api/sessions/' + id + '/history?includePending=' + includeFlag, + contentType: 'application/json', + processData: false + }); + } + + function addSessionInfoComment(sessionId, comment) { + return $.ajax({ + url: '/api/sessions/' + sessionId + "/details/comments", + type: "POST", + data: JSON.stringify({"comment": comment}), + dataType: 'json', + contentType: 'application/json' + }); + } + + function addSessionComment(sessionId, userId, comment) { + return $.ajax({ + url: '/api/sessions/' + sessionId + "/comments", + type: "POST", + data: JSON.stringify({"comment": comment, "user_id": userId}), + dataType: 'json', + contentType: 'application/json' + }); + } + + function addSessionLike(sessionId, userId) { + return $.ajax({ + url: '/api/sessions/' + sessionId + "/likes", + type: "POST", + data: JSON.stringify({"user_id": userId}), + dataType: 'json', + contentType: 'application/json' + }); + } + + function getRsvpRequests(sessionId) { + return $.ajax({ + url: '/api/rsvp_requests?session_id=' + sessionId, + type: "GET", + dataType: 'json', + contentType: 'application/json' + }); + } + + function submitRsvpRequest(sessionId, slotIds) { + return $.ajax({ + url: '/api/rsvp_requests', + type: "POST", + data: JSON.stringify({"session_id": sessionId, "rsvp_slots": slotIds}), + dataType: 'json', + contentType: 'application/json' + }); + } + + function updateRsvpRequest(rsvpRequestId, responses) { + return $.ajax({ + url: '/api/rsvp_requests/' + rsvpRequestId, + type: "POST", + data: JSON.stringify(responses), + dataType: 'json', + contentType: 'application/json' + }); + } + + function cancelRsvpRequest(sessionId, rsvpRequestId, cancelAll) { + var cancel = "yes"; + if (cancelAll) { + cancel = "all"; + } + return $.ajax({ + url: '/api/rsvp_requests/' + rsvpRequestId, + type: "DELETE", + data: JSON.stringify({"session_id": sessionId, "cancelled": cancelAll}), + dataType: 'json', + contentType: 'application/json' + }); + } + + function getOpenSessionSlots(sessionId, openOnly) { + var url = '/api/rsvp_slots?session_id=' + sessionId; + + if (openOnly) { + url += '&open_only=true'; + } + return $.ajax({ + type: "GET", + dataType: "json", + url: url, + contentType: 'application/json', + processData: false + }); + } + + function addRecordingComment(recordingId, userId, comment) { + return $.ajax({ + url: '/api/recordings/' + recordingId + "/comments", + type: "POST", + data: JSON.stringify({"comment": comment, "user_id": userId}), + dataType: 'json', + contentType: 'application/json' + }); + } + + function addRecordingLike(recordingId, claimedRecordingId, userId) { + return $.ajax({ + url: '/api/recordings/' + recordingId + "/likes", + type: "POST", + data: JSON.stringify({"user_id": userId, claimed_recording_id: claimedRecordingId}), + dataType: 'json', + contentType: 'application/json' + }); + } + + function addPlayablePlay(playableId, playableType, claimedRecordingId, userId) { + return $.ajax({ + url: '/api/users/' + playableId + "/plays", + type: "POST", + data: JSON.stringify({user_id: userId, claimed_recording_id: claimedRecordingId, playable_type: playableType}), + dataType: 'json', + contentType: 'application/json' + }); + } + + function updateFavorite(claimedRecordingId, favorite) { + return $.ajax({ + url: '/api/favorites/' + claimedRecordingId, + type: "POST", + data: JSON.stringify({favorite: favorite}), + dataType: 'json', + contentType: 'application/json' + }); + } + + function validateBand(band) { + return $.ajax({ + type: "POST", + dataType: "json", + url: '/api/bands/validate', + contentType: 'application/json', + processData: false, + data: JSON.stringify(band) + }); + } + + function getBand(bandId) { + return $.ajax({ + type: "GET", + dataType: "json", + url: '/api/bands/' + bandId, + contentType: 'application/json', + processData: false + }); + } + + function createBand(band) { + var deferred = $.ajax({ + type: "POST", + dataType: "json", + url: '/api/bands', + contentType: 'application/json', + processData: false, + data: JSON.stringify(band) + }); + + deferred.done(function () { + context.JK.GA.trackBand(context.JK.GA.BandActions.create); + context.JK.GA.trackBand(context.JK.GA.BandActions.join); + }); + + return deferred; + } + + function deleteBand(bandId) { + var url = "/api/bands/" + bandId; + return $.ajax({ + type: "DELETE", + dataType: "json", + url: url, + contentType: 'application/json', + processData: false + }); + } + + function updateBand(band) { + return $.ajax({ + type: "POST", + dataType: "json", + url: '/api/bands/' + band.id, + contentType: 'application/json', + processData: false, + data: JSON.stringify(band) + }); + } + + function createBandInvitation(bandId, userId) { + var bandInvitation = { + band_id: bandId, + user_id: userId + }; + + return $.ajax({ + type: "POST", + dataType: "json", + url: '/api/bands/' + bandId + "/invitations", + contentType: 'application/json', + processData: false, + data: JSON.stringify(bandInvitation) + }); + } + + function updateBandInvitation(bandId, invitationId, isAccepted) { + var deferred = $.ajax({ + type: "POST", + dataType: "json", + url: '/api/bands/' + bandId + "/invitations/" + invitationId, + contentType: 'application/json', + processData: false, + data: JSON.stringify({"accepted": isAccepted}) + }) + + if (isAccepted) { + deferred.done(function () { + context.JK.GA.trackBand(context.JK.GA.BandActions.join); + }) + } + + return deferred; + } + + function resendBandInvitation(bandId, invitationId) { + return $.ajax({ + type: "POST", + dataType: "json", + url: '/api/bands/' + bandId + "/invitations/" + invitationId, + contentType: 'application/json', + processData: false, + data: JSON.stringify({"resend": true}) + }) + } + + function removeBandMember(bandId, userId) { + var url = "/api/bands/" + bandId + "/musicians/" + userId; + return $.ajax({ + type: "DELETE", + dataType: "json", + url: url, + processData: false + }); + } + + function getBandMembers(bandId, hasPendingInvitation) { + var url = "/api/bands/" + bandId + "/musicians"; + + if (hasPendingInvitation) { + url += "?pending=true"; + } + + return $.ajax({ + type: "GET", + dataType: "json", + url: url, + processData: false + }); + } + + function getBands(userId) { + var url = "/api/users/" + userId + "/bands"; + return $.ajax({ + type: "GET", + dataType: "json", + url: url, + processData: false + }); + } + + + function getTeacher(options) { + return $.ajax({ + type: "GET", + dataType: "json", + url: '/api/teachers/detail?' + $.param(options), + contentType: 'application/json', + processData: false + }); + } + + function deleteTeacher(teacherId) { + var url = "/api/teachers/" + teacherId; + return $.ajax({ + type: "DELETE", + dataType: "json", + url: url, + contentType: 'application/json', + processData: false + }); + } + + function updateTeacher(teacher) { + console.log("Updating teacher", teacher) + var id = teacher && teacher["id"] + var url + if (id != null && typeof(id) != 'undefined') { + url = '/api/teachers/' + teacher.id + } else { + url = '/api/teachers' + } + + var deferred = $.ajax({ + type: "POST", + dataType: "json", + url: url, + contentType: 'application/json', + processData: false, + data: JSON.stringify(teacher) + }) + + return deferred + } + + function getSession(id) { + var url = "/api/sessions/" + id; + return $.ajax({ + type: "GET", + dataType: "json", + url: url, + processData: false + }); + } + + function deleteParticipant(clientId) { + var url = "/api/participants/" + clientId; + return $.ajax({ + type: "DELETE", + url: url + }); + } + + function login(options) { + var url = '/api/auths/login'; + + return $.ajax({ + type: "POST", + dataType: "json", + url: url, + processData: false, + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + function getUserAuthorizations(options) { + var id = getId(options); + + return $.ajax({ + type: "GET", + dataType: "json", + url: "/api/users/" + id + '/authorizations', + processData: false + }); + } + + function getGoogleAuth(options) { + var id = getId(options); + + return $.ajax({ + type: "GET", + dataType: "json", + url: "/api/users/authorizations/google", + processData: false + }); + } + + function getUserDetail(options) { + if (!options) { + options = {} + } + var id = getId(options); + var detail = null; + if (id != null && typeof(id) != 'undefined') { + detail = $.ajax({ + type: "GET", + dataType: "json", + url: "/api/users/" + id + '?' + $.param(options), + processData: false + }); + } + if (detail && context.JK.currentUserId == id) { + detail.done(function (user) { + window.UserActions.loaded(user) + }) + } + return detail; + } + + function getUserJamBlasters(options) { + if (!options) { + options = {} + } + var id = getId(options); + return $.ajax({ + type: "GET", + dataType: "json", + url: "/api/users/" + id + '/jamblasters?' + $.param(options), + processData: false + }); + } + + function getUserProfile(options) { + if (!options) { + options = {} + } + var id = getId(options); + return $.ajax({ + type: "GET", + dataType: "json", + url: "/api/users/" + id + "/profile" + '?' + $.param(options), + processData: false + }); + } + + function createAffiliatePartner(options) { + return $.ajax({ + type: "POST", + url: '/api/affiliate_partners', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + function getAffiliatePartnerData(userId) { + return $.ajax({ + type: "GET", + dataType: "json", + url: "/api/users/" + userId + "/affiliate_partner" + }); + } + + function postAffiliatePartnerData(userId, data) { + return $.ajax({ + type: "POST", + dataType: "json", + url: "/api/users/" + userId + "/affiliate_partner", + contentType: 'application/json', + processData: false, + data: JSON.stringify(data) + }); + } + + function getLinks(type, partner_id) { + var url = "/api/links/" + type; + + if (partner_id) { + url += '?affiliate_id=' + partner_id; + } + return $.ajax({ + type: "GET", + dataType: "json", + url: url + }); + } + + function getAffiliateSignups() { + return $.ajax({ + type: "GET", + dataType: "json", + url: "/api/affiliate_partners/signups" + }); + } + + function getAffiliateMonthly() { + return $.ajax({ + type: "GET", + dataType: "json", + url: "/api/affiliate_partners/monthly_earnings" + }); + } + + function getAffiliateQuarterly() { + return $.ajax({ + type: "GET", + dataType: "json", + url: "/api/affiliate_partners/quarterly_earnings" + }); + } + + function getAffiliatePayments() { + return $.ajax({ + type: "GET", + dataType: "json", + url: "/api/affiliate_partners/payments" + }); + } + + function getCities(options) { + var country = options['country'] + var region = options['region'] + + return $.ajax('/api/cities', { + data: {country: country, region: region}, + dataType: 'json' + }); + } + + function getRegions(options) { + var country = options["country"] + + return $.ajax('/api/regions', { + data: {country: country}, + dataType: 'json' + }); + } + + function getCountries() { + return $.ajax('/api/countries', { + dataType: 'json' + }); + } + + function getResolvedLocation() { + return $.ajax('/api/resolved_location', { + dataType: 'json' + }); + } + + function getInstruments(options) { + return $.ajax('/api/instruments', { + data: {}, + dataType: 'json' + }); + } + + function getGenres(options) { + return $.ajax('/api/genres', { + data: {}, + dataType: 'json' + }); + } + + function getSubjects(options) { + return $.ajax('/api/subjects', { + data: {}, + dataType: 'json' + }); + } + + function getLanguages(options) { + return $.ajax('/api/languages', { + data: {}, + dataType: 'json' + }); + } + + function updateUdpReachable(options) { + var id = getId(options); + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/users/" + id + "/udp_reachable", + data: JSON.stringify(options), + processData: false + }); + } + + function updateNetworkTesting(options) { + var id = getId(options); + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/users/" + id + "/is_network_testing", + data: JSON.stringify(options), + processData: false + }); + } + + function updateAvatar(options) { + var id = getId(options); + + var original_fpfile = options['original_fpfile']; + var cropped_fpfile = options['cropped_fpfile']; + var cropped_large_fpfile = options['cropped_large_fpfile']; + var crop_selection = options['crop_selection']; + + logger.debug(JSON.stringify({ + original_fpfile: original_fpfile, + cropped_fpfile: cropped_fpfile, + cropped_large_fpfile: cropped_large_fpfile, + crop_selection: crop_selection + })); + + var url = "/api/users/" + id + "/avatar"; + return $.ajax({ + type: "POST", + dataType: "json", + url: url, + contentType: 'application/json', + processData: false, + data: JSON.stringify({ + original_fpfile: original_fpfile, + cropped_fpfile: cropped_fpfile, + cropped_large_fpfile: cropped_large_fpfile, + crop_selection: crop_selection + }) + }); + } + + function deleteAvatar(options) { + var id = getId(options); + + var url = "/api/users/" + id + "/avatar"; + return $.ajax({ + type: "DELETE", + dataType: "json", + url: url, + contentType: 'application/json', + processData: false + }); + } + + function getFilepickerPolicy(options) { + var id = getId(options); + var handle = options && options["handle"]; + var convert = options && options["convert"] + + var url = "/api/users/" + id + "/filepicker_policy"; + + return $.ajax(url, { + data: {handle: handle, convert: convert}, + dataType: 'json' + }); + } + + function updateBandPhoto(options) { + var id = getId(options); + + var original_fpfile = options['original_fpfile']; + var cropped_fpfile = options['cropped_fpfile']; + var cropped_large_fpfile = options['cropped_large_fpfile']; + var crop_selection = options['crop_selection']; + + logger.debug(JSON.stringify({ + original_fpfile: original_fpfile, + cropped_fpfile: cropped_fpfile, + cropped_large_fpfile: cropped_large_fpfile, + crop_selection: crop_selection + })); + + var url = "/api/bands/" + id + "/photo"; + return $.ajax({ + type: "POST", + dataType: "json", + url: url, + contentType: 'application/json', + processData: false, + data: JSON.stringify({ + original_fpfile: original_fpfile, + cropped_fpfile: cropped_fpfile, + cropped_large_fpfile: cropped_large_fpfile, + crop_selection: crop_selection + }) + }); + } + + function deleteBandPhoto(options) { + var id = getId(options); + + var url = "/api/bands/" + id + "/photo"; + return $.ajax({ + type: "DELETE", + dataType: "json", + url: url, + contentType: 'application/json', + processData: false + }); + } + + function getBandPhotoFilepickerPolicy(options) { + var id = getId(options); + var handle = options && options["handle"]; + var convert = options && options["convert"] + + var url = "/api/bands/" + id + "/filepicker_policy"; + + return $.ajax(url, { + data: {handle: handle, convert: convert}, + dataType: 'json' + }); + } + + function getFriends(options) { + var id = getId(options); + return $.ajax({ + type: "GET", + url: '/api/users/' + id + '/friends', + dataType: 'json' + }); + } + + function removeFriend(options) { + var id = getId(options); + var friendId = options["friend_id"]; + + return $.ajax({ + type: "DELETE", + dataType: "json", + url: "/api/users/" + id + "/friends/" + friendId, + processData: false + }); + } + + /** NOTE: This is only for Musician, Fan, and Band Likes. Recording and + Session Likes have their own section below since unauthenticated users + are allowed to Like these entities. */ + function addLike(options) { + var id = getId(options); + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/users/" + id + "/likings", + data: JSON.stringify(options), + processData: false + }); + } - "use strict"; + function removeLike(likableId, options) { + var id = getId(options); + return $.ajax({ + type: "DELETE", + dataType: "json", + contentType: 'application/json', + url: "/api/users/" + id + "/likings", + data: JSON.stringify(options), + processData: false + }); + } - context.JK = context.JK || {}; - context.JK.Rest = function() { + function addFollowing(options) { + var id = getId(options); - var self = this; - var logger = context.JK.logger; + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/users/" + id + "/followings", + data: JSON.stringify(options), + processData: false + }); + } - function createJoinRequest(joinRequest) { - return $.ajax({ - type: "POST", - dataType: "json", - url: '/api/join_requests', - contentType: 'application/json', - processData: false, - data: JSON.stringify(joinRequest) - }); - } + function removeFollowing(followableId, options) { + var id = getId(options); + return $.ajax({ + type: "DELETE", + dataType: "json", + contentType: 'application/json', + url: "/api/users/" + id + "/followings/" + followableId, + processData: false + }); + } - function updateJoinRequest(joinRequestId, isApproved) { - return $.ajax({ - type: "PUT", - dataType: "json", - url: '/api/join_requests/' + joinRequestId, - contentType: 'application/json', - processData: false, - data: JSON.stringify({"approved": isApproved}) - }); - } + function getFollowings(options) { + var userId = getId(options); - function legacyCreateSession(options) { - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/sessions/legacy", - processData:false, - data: JSON.stringify(options) - }); - } + // FOLLOWINGS (USERS) + return $.ajax({ + type: "GET", + dataType: "json", + url: "/api/users/" + userId + "/followings", + processData: false + }); + } - function createScheduledSession(options) { - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/sessions", - processData: false, - data: JSON.stringify(options) - }); - } + function getFollowers(options) { + var userId = getId(options); + return $.ajax({ + type: "GET", + dataType: "json", + url: "/api/users/" + userId + "/followers", + processData: false + }); + } - function getBroadcastNotification(options) { - var userId = getId(options); - return $.ajax({ - type: "GET", - url: "/api/users/" + userId + "/broadcast_notification" - }); - } + function getBands(options) { + var userId = getId(options); - function quietBroadcastNotification(options) { - var userId = getId(options); - var broadcast_id = options.broadcast_id; - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/users/" + userId + "/broadcast_notification/" + broadcast_id + '/quiet', - data: JSON.stringify({}), - }); - } + return $.ajax({ + type: "GET", + dataType: "json", + url: "/api/users/" + userId + "/bands", + processData: false + }); + } - function uploadMusicNotations(formData) { - return $.ajax({ - type: "POST", - processData: false, - contentType: false, - dataType: "json", - cache: false, - url: "/api/music_notations", - data: formData - }); - } + function getBandFollowers(bandId) { + return $.ajax({ + type: "GET", + dataType: "json", + url: "/api/bands/" + bandId + "/followers", + processData: false + }); + } - function getMusicNotation(query) { - return $.ajax({ - type: "GET", - url: "/api/music_notations/"+query - }); - } + function getClientDownloads(options) { + return $.ajax({ + type: "GET", + url: '/api/artifacts/clients', + dataType: 'json' + }); + } - function deleteMusicNotation(options) { - return $.ajax({ - type: "DELETE", - url: "/api/music_notations/" +options.id - }); - } + /** check if the server is alive */ + function serverHealthCheck(options) { + return $.ajax({ + type: "GET", + url: "/api/healthcheck" + }); + } - function legacyJoinSession(options) { - var sessionId = options["session_id"]; - delete options["session_id"]; + function getId(options) { + var id = options && options["id"] - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/sessions/" + sessionId + "/participants/legacy", - data: JSON.stringify(options), - processData:false - }); - } + if (!id) { + id = context.JK.currentUserId; + } + else { + delete options["id"]; + } - function joinSession(options) { - var sessionId = options["session_id"]; - delete options["session_id"]; + return id; + } - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/sessions/" + sessionId + "/participants", - data: JSON.stringify(options), - processData: false - }); - } + function createEmailInvitations(emails, message) { + return $.ajax({ + type: "POST", + dataType: "json", + url: '/api/invited_users', + contentType: 'application/json', + processData: false, + data: JSON.stringify({ + emails: emails, + note: message + }) + }); + } - function cancelSession(options) { - var sessionId = options["session_id"]; - delete options["session_id"]; + function getMusicianInvites(options) { + return $.ajax({ + type: "GET", + dataType: "json", + data: options, + url: '/api/invitations' + }) + } - return $.ajax({ - type: "DELETE", - dataType: "JSON", - contentType: 'application/json', - url: "/api/sessions/" + sessionId, - data: JSON.stringify(options), - processData: false - }); - } + function createMusicianInvite(options) { + return $.ajax({ + type: "POST", + dataType: "json", + url: '/api/invitations', + contentType: 'application/json', + processData: false, + data: JSON.stringify(options) + }) + } - function findActiveSessions(query) { - return $.ajax({ - type: "GET", - url: "/api/sessions/active?" + $.param(query) - }); - } + function postFeedback(email, body) { + return $.ajax({ + type: "POST", + dataType: "json", + url: '/api/feedback', + contentType: 'application/json', + processData: false, + data: JSON.stringify({ + email: email, + body: body + }) + }); + } - function findInactiveSessions(query) { - return $.ajax({ - type: "GET", - url: "/api/sessions/inactive?" + $.param(query) - }); - } + function getFeeds(options) { + if (!options) { + options = {}; + } + return $.ajax({ + type: 'GET', + dataType: "json", + url: "/api/feeds?" + $.param(options), + processData: false + }) + } - function findScheduledSessions(query) { - return $.ajax({ - type: "GET", - url: "/api/sessions/scheduled?" + $.param(query) - }); - } + function getUserSyncs(options) { + if (!options) { + options = {}; + } + var userId = getId(options) + return $.ajax({ + type: 'GET', + dataType: "json", + url: "/api/users/" + userId + "/syncs?" + $.param(options), + processData: false + }) + } - function findScheduledRsvpSessions(query) { - return $.ajax({ - type: "GET", - url: "/api/sessions/scheduled_rsvp?" + $.param(query) - }); - } + function getUserSync(options) { + if (!options) { + options = {}; + } + var userId = getId(options) + var userSyncId = options['user_sync_id'] - function updateSession(id, newSession) { - return $.ajax({ - url: '/api/sessions/' + id, - type: "PUT", - data : newSession, - dataType : 'json' - }); - } + return $.ajax({ + type: 'GET', + dataType: "json", + url: "/api/users/" + userId + "/syncs/" + userSyncId, + processData: false + }) + } - function updateScheduledSession(id, newSession) { - return $.ajax({ - url: '/api/sessions/' + id, - type: "POST", - data: newSession, - dataType: 'json' - }); - } - - function getSessionHistory(id, includePending) { - var includeFlag = 'false'; - if (includePending) { - includeFlag = 'true'; - } - - return $.ajax({ - type: "GET", - dataType: "json", - url: '/api/sessions/' + id + '/history?includePending=' + includeFlag, - contentType: 'application/json', - processData: false - }); - } - - function addSessionInfoComment(sessionId, comment) { - return $.ajax({ - url: '/api/sessions/' + sessionId + "/details/comments", - type: "POST", - data : JSON.stringify({"comment": comment}), - dataType : 'json', - contentType: 'application/json' - }); - } - - function addSessionComment(sessionId, userId, comment) { - return $.ajax({ - url: '/api/sessions/' + sessionId + "/comments", - type: "POST", - data : JSON.stringify({"comment": comment, "user_id": userId}), - dataType : 'json', - contentType: 'application/json' - }); - } - - function addSessionLike(sessionId, userId) { - return $.ajax({ - url: '/api/sessions/' + sessionId + "/likes", - type: "POST", - data : JSON.stringify({"user_id": userId}), - dataType : 'json', - contentType: 'application/json' - }); - } - - function getRsvpRequests(sessionId) { - return $.ajax({ - url: '/api/rsvp_requests?session_id=' + sessionId, - type: "GET", - dataType : 'json', - contentType: 'application/json' - }); - } - - function submitRsvpRequest(sessionId, slotIds) { - return $.ajax({ - url: '/api/rsvp_requests', - type: "POST", - data : JSON.stringify({"session_id": sessionId, "rsvp_slots": slotIds}), - dataType : 'json', - contentType: 'application/json' - }); - } - - function updateRsvpRequest(rsvpRequestId, responses) { - return $.ajax({ - url: '/api/rsvp_requests/' + rsvpRequestId, - type: "POST", - data : JSON.stringify(responses), - dataType : 'json', - contentType: 'application/json' - }); - } - - function cancelRsvpRequest(sessionId, rsvpRequestId, cancelAll) { - var cancel = "yes"; - if (cancelAll) { - cancel = "all"; + function sendFriendRequest(app, userId, callback) { + var url = "/api/users/" + context.JK.currentUserId + "/friend_requests"; + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: url, + data: '{"friend_id":"' + userId + '"}', + processData: false, + success: function (response) { + if (callback) { + callback(userId); } - return $.ajax({ - url: '/api/rsvp_requests/' + rsvpRequestId, - type: "DELETE", - data : JSON.stringify({"session_id": sessionId, "cancelled": cancelAll}), - dataType : 'json', - contentType: 'application/json' - }); - } - - function getOpenSessionSlots(sessionId, openOnly) { - var url = '/api/rsvp_slots?session_id=' + sessionId; - - if (openOnly) { - url += '&open_only=true'; - } - return $.ajax({ - type: "GET", - dataType: "json", - url: url, - contentType: 'application/json', - processData: false - }); - } - - function addRecordingComment(recordingId, userId, comment) { - return $.ajax({ - url: '/api/recordings/' + recordingId + "/comments", - type: "POST", - data : JSON.stringify({"comment": comment, "user_id": userId}), - dataType : 'json', - contentType: 'application/json' - }); - } - - function addRecordingLike(recordingId, claimedRecordingId, userId) { - return $.ajax({ - url: '/api/recordings/' + recordingId + "/likes", - type: "POST", - data : JSON.stringify({"user_id": userId, claimed_recording_id: claimedRecordingId}), - dataType : 'json', - contentType: 'application/json' - }); - } - - function addPlayablePlay(playableId, playableType, claimedRecordingId, userId) { - return $.ajax({ - url: '/api/users/' + playableId + "/plays", - type: "POST", - data : JSON.stringify({user_id: userId, claimed_recording_id: claimedRecordingId, playable_type: playableType}), - dataType : 'json', - contentType: 'application/json' - }); - } - - function updateFavorite(claimedRecordingId, favorite) { - return $.ajax({ - url: '/api/favorites/' + claimedRecordingId, - type: "POST", - data : JSON.stringify({favorite: favorite}), - dataType : 'json', - contentType: 'application/json' - }); - } - - function validateBand(band) { - return $.ajax({ - type: "POST", - dataType: "json", - url: '/api/bands/validate', - contentType: 'application/json', - processData: false, - data: JSON.stringify(band) - }); - } - - function getBand(bandId) { - return $.ajax({ - type: "GET", - dataType: "json", - url: '/api/bands/' + bandId, - contentType: 'application/json', - processData: false - }); - } - - function createBand(band) { - var deferred = $.ajax({ - type: "POST", - dataType: "json", - url: '/api/bands', - contentType: 'application/json', - processData: false, - data: JSON.stringify(band) - }); - - deferred.done(function() { - context.JK.GA.trackBand(context.JK.GA.BandActions.create); - context.JK.GA.trackBand(context.JK.GA.BandActions.join); - }); - - return deferred; - } - - function deleteBand(bandId) { - var url = "/api/bands/" + bandId; - return $.ajax({ - type: "DELETE", - dataType: "json", - url: url, - contentType: 'application/json', - processData:false - }); - } - - function updateBand(band) { - return $.ajax({ - type: "POST", - dataType: "json", - url: '/api/bands/' + band.id, - contentType: 'application/json', - processData: false, - data: JSON.stringify(band) - }); - } - - function createBandInvitation(bandId, userId) { - var bandInvitation = { - band_id: bandId, - user_id: userId - }; - - return $.ajax({ - type: "POST", - dataType: "json", - url: '/api/bands/' + bandId + "/invitations", - contentType: 'application/json', - processData: false, - data: JSON.stringify(bandInvitation) - }); - } - - function updateBandInvitation(bandId, invitationId, isAccepted) { - var deferred = $.ajax({ - type: "POST", - dataType: "json", - url: '/api/bands/' + bandId + "/invitations/" + invitationId, - contentType: 'application/json', - processData: false, - data: JSON.stringify({"accepted": isAccepted}) - }) - - if(isAccepted) { - deferred.done(function() { - context.JK.GA.trackBand(context.JK.GA.BandActions.join); - }) - } - - return deferred; - } - - function resendBandInvitation(bandId, invitationId) { - return $.ajax({ - type: "POST", - dataType: "json", - url: '/api/bands/' + bandId + "/invitations/" + invitationId, - contentType: 'application/json', - processData: false, - data: JSON.stringify({"resend": true}) - }) - } - - function removeBandMember(bandId, userId) { - var url = "/api/bands/" + bandId + "/musicians/" + userId; - return $.ajax({ - type: "DELETE", - dataType: "json", - url: url, - processData:false - }); - } - - function getBandMembers(bandId, hasPendingInvitation) { - var url = "/api/bands/" + bandId + "/musicians"; - - if (hasPendingInvitation) { - url += "?pending=true"; - } - - return $.ajax({ - type: "GET", - dataType: "json", - url: url, - processData:false - }); - } - - function getBands(userId) { - var url = "/api/users/" + userId + "/bands"; - return $.ajax({ - type: "GET", - dataType: "json", - url: url, - processData:false - }); - } - - - function getTeacher(options) { - return $.ajax({ - type: "GET", - dataType: "json", - url: '/api/teachers/detail?'+ $.param(options), - contentType: 'application/json', - processData: false - }); - } - - function deleteTeacher(teacherId) { - var url = "/api/teachers/" + teacherId; - return $.ajax({ - type: "DELETE", - dataType: "json", - url: url, - contentType: 'application/json', - processData:false - }); - } - - function updateTeacher(teacher) { - console.log("Updating teacher", teacher) - var id = teacher && teacher["id"] - var url - if (id != null && typeof(id) != 'undefined') { - url = '/api/teachers/' + teacher.id - } else { - url = '/api/teachers' - } - - var deferred = $.ajax({ - type: "POST", - dataType: "json", - url: url, - contentType: 'application/json', - processData: false, - data: JSON.stringify(teacher) - }) - - return deferred - } - - function getSession(id) { - var url = "/api/sessions/" + id; - return $.ajax({ - type: "GET", - dataType: "json", - url: url, - processData: false - }); - } - - function deleteParticipant(clientId) { - var url = "/api/participants/" + clientId; - return $.ajax({ - type: "DELETE", - url: url - }); - } - - function login(options) { - var url = '/api/auths/login'; - - return $.ajax({ - type: "POST", - dataType: "json", - url: url, - processData: false, - contentType: 'application/json', - data: JSON.stringify(options) - }) - } - - function getUserAuthorizations(options) { - var id = getId(options); - - return $.ajax({ - type: "GET", - dataType: "json", - url: "/api/users/" + id + '/authorizations', - processData: false - }); - } - - function getGoogleAuth(options) { - var id = getId(options); - - return $.ajax({ - type: "GET", - dataType: "json", - url: "/api/users/authorizations/google", - processData: false - }); - } - - function getUserDetail(options) { - if(!options) { - options = {} - } - var id = getId(options); - var detail = null; - if (id != null && typeof(id) != 'undefined') { - detail = $.ajax({ - type: "GET", - dataType: "json", - url: "/api/users/" + id + '?' + $.param(options), - processData: false - }); - } - if(detail && context.JK.currentUserId == id) { - detail.done(function(user) { - window.UserActions.loaded(user) - }) - } - return detail; - } - - function getUserJamBlasters(options) { - if(!options) { - options = {} - } - var id = getId(options); - return $.ajax({ - type: "GET", - dataType: "json", - url: "/api/users/" + id + '/jamblasters?' + $.param(options), - processData: false - }); - } - - function getUserProfile(options) { - if (!options) { - options = {} - } - var id = getId(options); - return $.ajax({ - type: "GET", - dataType: "json", - url: "/api/users/" + id + "/profile" + '?' + $.param(options), - processData: false - }); - } - - function createAffiliatePartner(options) { - return $.ajax({ - type: "POST", - url: '/api/affiliate_partners', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options) - }) - } - - function getAffiliatePartnerData(userId) { - return $.ajax({ - type: "GET", - dataType: "json", - url: "/api/users/"+userId+"/affiliate_partner" - }); - } - - function postAffiliatePartnerData(userId, data) { - return $.ajax({ - type: "POST", - dataType: "json", - url: "/api/users/"+userId+"/affiliate_partner", - contentType: 'application/json', - processData:false, - data: JSON.stringify(data) - }); - } - - function getLinks(type, partner_id) { - var url = "/api/links/" + type; - - if(partner_id) { - url += '?affiliate_id=' + partner_id; - } - return $.ajax({ - type: "GET", - dataType: "json", - url: url - }); - } - - function getAffiliateSignups() { - return $.ajax({ - type: "GET", - dataType: "json", - url: "/api/affiliate_partners/signups" - }); - } - - function getAffiliateMonthly() { - return $.ajax({ - type: "GET", - dataType: "json", - url: "/api/affiliate_partners/monthly_earnings" - }); - } - - function getAffiliateQuarterly() { - return $.ajax({ - type: "GET", - dataType: "json", - url: "/api/affiliate_partners/quarterly_earnings" - }); - } - - function getAffiliatePayments() { - return $.ajax({ - type: "GET", - dataType: "json", - url: "/api/affiliate_partners/payments" - }); - } - - function getCities(options) { - var country = options['country'] - var region = options['region'] - - return $.ajax('/api/cities', { - data : { country: country, region: region }, - dataType : 'json' - }); - } - - function getRegions(options) { - var country = options["country"] - - return $.ajax('/api/regions', { - data : { country: country}, - dataType : 'json' - }); - } - - function getCountries() { - return $.ajax('/api/countries', { - dataType : 'json' - }); - } - - function getResolvedLocation() { - return $.ajax('/api/resolved_location', { - dataType: 'json' - }); - } - - function getInstruments(options) { - return $.ajax('/api/instruments', { - data : { }, - dataType : 'json' - }); - } - - function getGenres(options) { - return $.ajax('/api/genres', { - data: { }, - dataType: 'json' - }); - } - - function getSubjects(options) { - return $.ajax('/api/subjects', { - data: { }, - dataType: 'json' - }); - } - - function getLanguages(options) { - return $.ajax('/api/languages', { - data: { }, - dataType: 'json' - }); - } - - function updateUdpReachable(options) { - var id = getId(options); - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/users/" + id + "/udp_reachable", - data: JSON.stringify(options), - processData: false - }); - } - - function updateNetworkTesting(options) { - var id = getId(options); - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/users/" + id + "/is_network_testing", - data: JSON.stringify(options), - processData: false - }); - } - - function updateAvatar(options) { - var id = getId(options); - - var original_fpfile = options['original_fpfile']; - var cropped_fpfile = options['cropped_fpfile']; - var cropped_large_fpfile = options['cropped_large_fpfile']; - var crop_selection = options['crop_selection']; - - logger.debug(JSON.stringify({ - original_fpfile : original_fpfile, - cropped_fpfile : cropped_fpfile, - cropped_large_fpfile : cropped_large_fpfile, - crop_selection : crop_selection - })); - - var url = "/api/users/" + id + "/avatar"; - return $.ajax({ - type: "POST", - dataType: "json", - url: url, - contentType: 'application/json', - processData:false, - data: JSON.stringify({ - original_fpfile : original_fpfile, - cropped_fpfile : cropped_fpfile, - cropped_large_fpfile : cropped_large_fpfile, - crop_selection : crop_selection - }) - }); - } - - function deleteAvatar(options) { - var id = getId(options); - - var url = "/api/users/" + id + "/avatar"; - return $.ajax({ - type: "DELETE", - dataType: "json", - url: url, - contentType: 'application/json', - processData:false - }); - } - - function getFilepickerPolicy(options) { - var id = getId(options); - var handle = options && options["handle"]; - var convert = options && options["convert"] - - var url = "/api/users/" + id + "/filepicker_policy"; - - return $.ajax(url, { - data : { handle : handle, convert: convert }, - dataType : 'json' - }); - } - - function updateBandPhoto(options) { - var id = getId(options); - - var original_fpfile = options['original_fpfile']; - var cropped_fpfile = options['cropped_fpfile']; - var cropped_large_fpfile = options['cropped_large_fpfile']; - var crop_selection = options['crop_selection']; - - logger.debug(JSON.stringify({ - original_fpfile : original_fpfile, - cropped_fpfile : cropped_fpfile, - cropped_large_fpfile : cropped_large_fpfile, - crop_selection : crop_selection - })); - - var url = "/api/bands/" + id + "/photo"; - return $.ajax({ - type: "POST", - dataType: "json", - url: url, - contentType: 'application/json', - processData:false, - data: JSON.stringify({ - original_fpfile : original_fpfile, - cropped_fpfile : cropped_fpfile, - cropped_large_fpfile : cropped_large_fpfile, - crop_selection : crop_selection - }) - }); - } - - function deleteBandPhoto(options) { - var id = getId(options); - - var url = "/api/bands/" + id + "/photo"; - return $.ajax({ - type: "DELETE", - dataType: "json", - url: url, - contentType: 'application/json', - processData:false - }); - } - - function getBandPhotoFilepickerPolicy(options) { - var id = getId(options); - var handle = options && options["handle"]; - var convert = options && options["convert"] - - var url = "/api/bands/" + id + "/filepicker_policy"; - - return $.ajax(url, { - data : { handle : handle, convert: convert }, - dataType : 'json' - }); - } - - function getFriends(options) { - var id = getId(options); - return $.ajax({ - type: "GET", - url: '/api/users/' + id + '/friends', - dataType: 'json' - }); - } - - function removeFriend(options) { - var id = getId(options); - var friendId = options["friend_id"]; - - return $.ajax({ - type: "DELETE", - dataType: "json", - url: "/api/users/" + id + "/friends/" + friendId, - processData: false - }); - } - - /** NOTE: This is only for Musician, Fan, and Band Likes. Recording and - Session Likes have their own section below since unauthenticated users - are allowed to Like these entities. - */ - function addLike(options) { - var id = getId(options); - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/users/" + id + "/likings", - data: JSON.stringify(options), - processData: false - }); - } - - function removeLike(likableId, options) { - var id = getId(options); - return $.ajax({ - type: "DELETE", - dataType: "json", - contentType: 'application/json', - url: "/api/users/" + id + "/likings", - data: JSON.stringify(options), - processData: false - }); - } - - function addFollowing(options) { - var id = getId(options); - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/users/" + id + "/followings", - data: JSON.stringify(options), - processData: false - }); - } - - function removeFollowing(followableId, options) { - var id = getId(options); - return $.ajax({ - type: "DELETE", - dataType: "json", - contentType: 'application/json', - url: "/api/users/" + id + "/followings/" + followableId, - processData: false - }); - } - - function getFollowings(options) { - var userId = getId(options); - - // FOLLOWINGS (USERS) - return $.ajax({ - type: "GET", - dataType: "json", - url: "/api/users/" + userId + "/followings", - processData:false - }); - } - - function getFollowers(options) { - var userId = getId(options); - return $.ajax({ - type: "GET", - dataType: "json", - url: "/api/users/" + userId + "/followers", - processData:false - }); - } - - function getBands(options) { - var userId = getId(options); - - return $.ajax({ - type: "GET", - dataType: "json", - url: "/api/users/" + userId + "/bands", - processData:false - }); - } - - function getBandFollowers(bandId) { - return $.ajax({ - type: "GET", - dataType: "json", - url: "/api/bands/" + bandId + "/followers", - processData:false - }); - } - - function getClientDownloads(options) { - - return $.ajax({ - type: "GET", - url: '/api/artifacts/clients', - dataType: 'json' - }); - } - - /** check if the server is alive */ - function serverHealthCheck(options) { - return $.ajax({ - type: "GET", - url: "/api/healthcheck" - }); - } - - function getId(options) { - var id = options && options["id"] - - if(!id) { - id = context.JK.currentUserId; - } - else { - delete options["id"]; - } - - return id; - } - - function createEmailInvitations(emails, message) { - return $.ajax({ - type: "POST", - dataType: "json", - url: '/api/invited_users', - contentType: 'application/json', - processData:false, - data: JSON.stringify({ - emails : emails, - note: message - }) - }); - } - - function getMusicianInvites(options) { - return $.ajax({ - type: "GET", - dataType: "json", - data: options, - url: '/api/invitations' - }) - } - - function createMusicianInvite(options) { - return $.ajax({ - type: "POST", - dataType: "json", - url: '/api/invitations', - contentType: 'application/json', - processData:false, - data: JSON.stringify(options) - }) - } - - function postFeedback(email, body) { - return $.ajax({ - type: "POST", - dataType: "json", - url: '/api/feedback', - contentType: 'application/json', - processData:false, - data: JSON.stringify({ - email : email, - body: body - }) - }); - } - - function getFeeds(options) { - if(!options) { options = {}; } - return $.ajax({ - type: 'GET', - dataType: "json", - url: "/api/feeds?" + $.param(options), - processData:false - }) - } - - function getUserSyncs(options) { - if(!options) { options = {}; } - var userId = getId(options) - return $.ajax({ - type: 'GET', - dataType: "json", - url: "/api/users/" + userId + "/syncs?" + $.param(options), - processData:false - }) - } - - function getUserSync(options) { - if(!options) { options = {}; } - var userId = getId(options) - var userSyncId = options['user_sync_id'] - - return $.ajax({ - type: 'GET', - dataType: "json", - url: "/api/users/" + userId + "/syncs/" + userSyncId, - processData:false - }) - } - - function sendFriendRequest(app, userId, callback) { - var url = "/api/users/" + context.JK.currentUserId + "/friend_requests"; - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: url, - data: '{"friend_id":"' + userId + '"}', - processData: false, - success: function(response) { - if (callback) { - callback(userId); - } - context.JK.GA.trackFriendConnect(context.JK.GA.FriendConnectTypes.request); - }, - error: app.ajaxError - }); - } - - function getFriendRequest(options) { - var id = getId(options); - var friendRequestId = options["friend_request_id"]; - - var deferred = $.ajax({ - type: "GET", - dataType: "json", - contentType: 'application/json', - url: "/api/users/" + id + "/friend_requests/" + friendRequestId, - processData: false - }); - - return deferred; - } - - function acceptFriendRequest(options) { - var id = getId(options); - var friendRequestId = options["friend_request_id"]; - var status = options["status"]; - - var friend_request = { status: status }; - - var deferred = $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/users/" + id + "/friend_requests/" + friendRequestId, - data: JSON.stringify(friend_request), - processData: false - }); - - deferred.done(function() { - context.JK.GA.trackFriendConnect(context.JK.GA.FriendConnectTypes.accept); - }); - - return deferred; - } - - function userDownloadedClient(options) { - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/users/progression/downloaded_client", - processData: false - }); - } - - function userCertifiedGear(options) { - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/users/progression/certified_gear", - processData: false, - data: JSON.stringify({ - success: options.success, - reason: options.reason - }) - }); - } - - function userSocialPromoted(options) { - var id = getId(options); - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/users/progression/social_promoted", - processData: false - }); - } - - function userOpenedJamTrackWebPlayer(options) { - var id = getId(options); - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/users/progression/opened_jamtrack_web_player", - processData: false - }); - } - - function postUserEvent(options) { - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/users/event/record", - data: JSON.stringify(options), - processData: false - }); - } - - function signout() { - return $.ajax({ - type: "DELETE", - dataType: "json", - url: '/signout', - contentType: 'application/json' - }); - } - - function updateUser(options) { - options = options || {}; - var id = getId(options); - - delete options['id']; - - var deferred = $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/users/" + id, - data: JSON.stringify(options), - processData: false - }); - - deferred.done(function(user) { - context.JK.currentUserFreeJamTrack = user.show_free_jamtrack - window.UserActions.loaded(user) - }) - - return deferred; - - } - - function startRecording(options) { - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/recordings/start", - data: JSON.stringify(options) - }) - } - - function stopRecording(options) { - var recordingId = options["id"] - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/recordings/" + recordingId + "/stop", - data: JSON.stringify(options) - }) - } - - function markRecordedBackingTrackSilent(options) { - var recordingId = options["recording_id"]; - var trackId = options["backing_track_id"]; - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - data: {}, - url: "/api/recordings/" + recordingId + "/backing_tracks/" + trackId + '/silent' - }); - } - function getRecordedTrack(options) { - var recordingId = options["recording_id"]; - var trackId = options["track_id"]; - - return $.ajax({ - type: "GET", - dataType: "json", - contentType: 'application/json', - url: "/api/recordings/" + recordingId + "/tracks/" + trackId - }); - } - - function getRecordedBackingTrack(options) { - var recordingId = options["recording_id"]; - var trackId = options["track_id"]; - - return $.ajax({ - type: "GET", - dataType: "json", - contentType: 'application/json', - url: "/api/recordings/" + recordingId + "/backing_tracks/" + trackId - }); - } - - function getRecording(options) { - var recordingId = options["id"]; - - return $.ajax({ - type: "GET", - dataType: "json", - contentType: 'application/json', - url: "/api/recordings/" + recordingId - }); - } - - function getClaimedRecordings(options) { - return $.ajax({ - type: "GET", - dataType: "json", - contentType: 'application/json', - url: "/api/claimed_recordings", - data: options - }); - } - - function getClaimedRecording(id) { - return $.ajax({ - type: "GET", - dataType: "json", - contentType: 'application/json', - url: "/api/claimed_recordings/" + id - }); - } - - function updateClaimedRecording(options) { - var claimedRecordingId = options["id"]; - return $.ajax({ - type: "PUT", - dataType: "json", - url: '/api/claimed_recordings/' + claimedRecordingId, - contentType: 'application/json', - processData: false, - data: JSON.stringify(options) - }); - } - - function deleteClaimedRecording(id) { - return $.ajax({ - type: "DELETE", - dataType: "json", - contentType: 'application/json', - url: "/api/claimed_recordings/" + id - }); - } - - function deleteRecordingClaim(id) { - return $.ajax({ - type: "DELETE", - dataType: "json", - contentType: 'application/json', - url: "/api/recordings/" + id + "/claim" - }); - } - - function claimRecording(options) { - var recordingId = options["id"]; - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/recordings/" + recordingId + "/claim", - data: JSON.stringify(options) - }) - } - - function startPlayClaimedRecording(options) { - var musicSessionId = options["id"]; - var claimedRecordingId = options["claimed_recording_id"]; - delete options["id"]; - delete options["claimed_recording_id"]; - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/sessions/" + musicSessionId + "/claimed_recording/" + claimedRecordingId + "/start", - data: JSON.stringify(options) - }) - } - - function stopPlayClaimedRecording(options) { - var musicSessionId = options["id"]; - var claimedRecordingId = options["claimed_recording_id"]; - delete options["id"]; - delete options["claimed_recording_id"]; - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/sessions/" + musicSessionId + "/claimed_recording/" + claimedRecordingId + "/stop", - data: JSON.stringify(options) - }) - } - - function openBackingTrack(options) { - var musicSessionId = options["id"]; - delete options["id"]; - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/sessions/" + musicSessionId + "/backing_tracks/open", - data: JSON.stringify(options) - }) - } - - function closeBackingTrack(options) { - var musicSessionId = options["id"]; - delete options["id"]; - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/sessions/" + musicSessionId + "/backing_tracks/close", - data: JSON.stringify(options) - }) - } - - function markMixdownActive(options) { - var id = options["id"]; - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/jamtracks/" + id + "/mixdowns/active", - data: JSON.stringify(options) - }) - } - - function createMixdown(options) { - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/mixdowns/", - data: JSON.stringify(options) - }) - } - - function editMixdown(options) { - var id = options["id"]; - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/mixdowns/" + id , - data: JSON.stringify(options) - }) - } - - function deleteMixdown(options) { - var id = options["id"]; - - return $.ajax({ - type: "DELETE", - dataType: "json", - contentType: 'application/json', - url: "/api/mixdowns/" + id - }) - } - - function getMixdown(options) { - var id = options["id"]; - - return $.ajax({ - type: "GET", - dataType: "json", - contentType: 'application/json', - url: "/api/mixdowns/" + id - }) - } - - function getMixdownPackage(options) { - var id = options["id"]; - - return $.ajax({ - type: "GET", - dataType: "json", - contentType: 'application/json', - url: "/api/mixdown_packages/" + id - }) - } - - function enqueueMixdown(options) { - var id = options["id"]; - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/mixdowns/" + id + '/enqueue' , - data: JSON.stringify(options) - }) - } - - function openJamTrack(options) { - var musicSessionId = options["id"]; - var jamTrackId = options["jam_track_id"]; - delete options["id"]; - delete options["jam_track_id"]; - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/sessions/" + musicSessionId + "/jam_tracks/" + jamTrackId + "/open", - data: JSON.stringify(options) - }) - } - - function playJamTrack(jamTrackId) { - return $.ajax({ - type: "POST", - url: '/api/jamtracks/played/' + jamTrackId, - dataType: "json", - contentType: 'application/json' - }); - } - - function closeJamTrack(options) { - var musicSessionId = options["id"]; - delete options["id"]; - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/sessions/" + musicSessionId + "/jam_tracks/close", - data: JSON.stringify(options) - }) - } - - function openMetronome(options) { - var musicSessionId = options["id"]; - delete options["id"]; - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/sessions/" + musicSessionId + "/metronome/open", - data: JSON.stringify(options) - }) - } - - function closeMetronome(options) { - var musicSessionId = options["id"]; - delete options["id"]; - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/sessions/" + musicSessionId + "/metronome/close", - data: JSON.stringify(options) - }) - } - - function discardRecording(options) { - var recordingId = options["id"]; - - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/recordings/" + recordingId + "/discard", - data: JSON.stringify(options) - }) - } - - function putTrackSyncChange(options) { - var musicSessionId = options["id"] - delete options["id"]; - - return $.ajax({ - type: "PUT", - dataType: "json", - url: '/api/sessions/' + musicSessionId + '/tracks', - contentType: 'application/json', - processData: false, - data: JSON.stringify(options) - }); - } - - function getShareSession(options) { - var id = getId(options); - var provider = options['provider']; - delete options['provider'] - - return $.ajax({ - type: "GET", - dataType: "json", - contentType: 'application/json', - url: "/api/users/" + id + "/share/session/" + provider, - data: options - }) - } - - function getShareRecording(options) { - var id = getId(options); - var provider = options['provider']; - delete options['provider'] - - return $.ajax({ - type: "GET", - dataType: "json", - contentType: 'application/json', - url: "/api/users/" + id + "/share/recording/" + provider, - data: options - }) - } - - function tweet(options) { - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: "/api/twitter/tweet", - data: JSON.stringify(options) - }) - } - - function createFbInviteUrl() { - return $.ajax({ - type: "GET", - url: '/api/invited_users/facebook', - dataType: "json", - contentType: 'application/json' - }); - } - - function createTextMessage(options) { - var id = getId(options); - return $.ajax({ - type: "POST", - url: '/api/text_messages', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options) - }); - } - - function getTextMessages(options) { - if(!options) options = {}; - var id = getId(options); - return $.ajax({ - type: "GET", - url: '/api/text_messages?' + $.param(options), - dataType: "json", - contentType: 'application/json' - }); - } - - function getNotifications(options) { - if(!options) options = {}; - var id = getId(options); - return $.ajax({ - type: "GET", - url: '/api/users/' + id + '/notifications?' + $.param(options), - dataType: "json", - contentType: 'application/json' - }); - } - - function createChatMessage(data) { - return $.ajax({ - type: "POST", - url: '/api/chat', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(data) - }); - } - - function getChatMessages(options) { - return $.ajax({ - type: "GET", - url: '/api/chat?' + $.param(options), - dataType: "json", - contentType: 'application/json' - }) - }; - - function createDiagnostic(options) { - var data = null; - try { - data = JSON.stringify(options) - } - catch(e) { - data = JSON.stringify({data_error: "unable to JSON.stringify debug data:" + e.toString()}) - } - return $.ajax({ - type: "POST", - url: '/api/diagnostics', - dataType: "json", - contentType: 'application/json', - data: data, - }); - } - - function getLatencyTester(options) { - return $.ajax({ - type: "GET", - url: '/api/latency_testers', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options) - }); - } - - function updateAudioLatency(options) { - var id = getId(options); - return $.ajax({ - type: "POST", - url: '/api/users/' + id + '/audio_latency', - dataType: "json", - contentType: 'application/json', - data: options, - }); - } - - function getJamTrack(options) { - return $.ajax({ - type: "GET", - url: '/api/jamtracks/' + options['plan_code'] + '?' + $.param(options), - dataType: "json", - contentType: 'application/json' - }); - } - - function getJamTrackWithArtistInfo(options) { - return $.ajax({ - type: "GET", - url: '/api/jamtracks/band/' + options['plan_code'] + '?' + $.param(options), - dataType: "json", - contentType: 'application/json' - }); - } - - function getJamTracks(options) { - return $.ajax({ - type: "GET", - url: '/api/jamtracks?' + $.param(options), - dataType: "json", - contentType: 'application/json' - }); - } - - function autocompleteJamTracks(options) { - return $.ajax({ - type: "GET", - url: '/api/jamtracks/autocomplete?' + $.param(options), - dataType: "json", - contentType: 'application/json' - }); - } - - function getJamTrackArtists(options) { - return $.ajax({ - type: "GET", - url: '/api/jamtracks/artists?' + $.param(options), - dataType: "json", - contentType: 'application/json' - }); - } - - function getJamTrackRight(options) { - var jamTrackId = options['id']; - - return $.ajax({ - type: "GET", - url: '/api/jamtracks/rights/' + jamTrackId + '?' + $.param(options), - dataType: "json", - contentType: 'application/json' - }) - } - - function enqueueJamTrack(options) { - var jamTrackId = options['id']; - delete options['id'] - - return $.ajax({ - type: "POST", - url: '/api/jamtracks/enqueue/' + jamTrackId, - dataType: "json", - data: options - }); - } - - function getPurchasedJamTracks(options) { - return $.ajax({ - type: "GET", - url: '/api/jamtracks/purchased?' + $.param(options), - dataType: "json", - contentType: 'application/json' - }); - } - - function getPaymentHistory(options) { - return $.ajax({ - type: "GET", - url: '/api/recurly/payment_history', - dataType: "json", - contentType: 'application/json' - }); - } - - function getSalesHistory(options) { - return $.ajax({ - type: "GET", - url: '/api/payment_histories?' + $.param(options), - dataType: "json", - contentType: 'application/json' - }); - } - - function getBackingTracks(options) { - return $.ajax({ - type: "GET", - url: '/api/backing_tracks?' + $.param(options), - dataType: "json", - contentType: 'application/json' - }); - } - - function addJamtrackToShoppingCart(options) { - var deferred = $.ajax({ - type: "POST", - url: '/api/shopping_carts/add_jamtrack?' + $.param(options), - dataType: "json", - contentType: 'application/json' - }); - - deferred.done(function(response) { - window.UserActions.modify(response) - }) - return deferred - } - - function addGiftCardToShoppingCart(options) { - var deferred = $.ajax({ - type: "POST", - url: '/api/shopping_carts/add_gift_card?' + $.param(options), - dataType: "json", - contentType: 'application/json' - }); - - return deferred - } - - function getShoppingCarts() { - // the need for the time de-duplicator indicates we are doing something wrong on the server - return $.ajax({ - type: "GET", - url: '/api/shopping_carts?time=' + new Date().getTime(), - dataType: "json", - contentType: 'application/json' - }); - } - - function removeShoppingCart(options) { - var deferred = $.ajax({ - type: "DELETE", - url: '/api/shopping_carts?' + $.param(options), - dataType: "json", - contentType: 'application/json' - }) - - deferred.done(function(response) { - window.UserActions.modify(response) - }) - return deferred - } - - function clearShoppingCart(options) { - return $.ajax({ - type: "DELETE", - url: '/api/shopping_carts/clear_all', - dataType: "json", - contentType: 'application/json' - }) - } - - function getRecurlyAccount() { - return $.ajax({ - type: "GET", - url: '/api/recurly/get_account', - dataType: "json", - contentType: 'application/json' - }); - } - - function createRecurlyAccount(options) { - return $.ajax({ - type: "POST", - url: '/api/recurly/create_account?' + $.param(options), - dataType: "json", - contentType: 'application/json' - }); - } - - function getBillingInfo() { - return $.ajax({ - type: "GET", - url: '/api/recurly/billing_info', - dataType: "json", - contentType: 'application/json' - }); - } - - function updateBillingInfo(options) { - return $.ajax({ - type: "PUT", - url: '/api/recurly/update_billing_info?' + $.param({billing_info: options}), - dataType: "json", - //data: JSON.stringify({"billing_info": $.param(options)}), - contentType: 'application/json' - }); - } - - function placeOrder() { - return $.ajax({ - type: "POST", - url: '/api/recurly/place_order', - dataType: "json", - contentType: 'application/json' - }); - } - - function searchMusicians(query) { - return $.ajax({ - type: "GET", - url: "/api/search.json?" + $.param(query) - }); - } - - function searchTeachers(query) { - return $.ajax({ - type: "GET", - url: "/api/teachers?" + $.param(query), - dataType: "json", - contentType: 'application/json' - }); - } - - function getMusicianSearchFilter(query) { - var qarg = query === undefined ? '' : query; - return $.get("/api/search/musicians.json?"+qarg); - } - - function postMusicianSearchFilter(query) { - return $.ajax({ - type: "POST", - url: "/api/search/musicians.json", - data: query - }); - } - - function getBandSearchFilter(query) { - var qarg = query === undefined ? '' : query; - return $.get("/api/search/bands.json?"+qarg); - } - - function postBandSearchFilter(query) { - return $.ajax({ - type: "POST", - url: "/api/search/bands.json", - data: query - }); - } - - function getMount(options) { - var id = getId(options); - return $.ajax({ - type: "GET", - url: '/api/icecast/mount/' + id, - dataType: "json", - contentType: 'application/json' - }); - } - - function createSourceChange(options) { - var mountId = options['mount_id']; - - return $.ajax({ - type: "POST", - url: '/api/icecast/mount/' + mountId + '/source_change', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options), - }); - } - - function validateUrlSite(url, sitetype) { - return $.ajax({ - type: "GET", - url: '/api/data_validation?sitetype='+sitetype+'&data=' + encodeURIComponent(url), - contentType: 'application/json' - }); - } - - function addRecordingTimeline(recordingId, data) { - return $.ajax({ - type: "POST", - url: '/api/recordings/' + recordingId + '/timeline', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(data), - }); - } - - - function addRecordingVideoData(recordingId, data) { - return $.ajax({ - type: "POST", - url: '/api/recordings/' + recordingId + '/video_data', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(data), - }); - } - - function deleteRecordingVideoData(recordingId) { - return $.ajax({ - type: "DELETE", - url: '/api/recordings/' + recordingId + '/video_data', - dataType: "json", - contentType: 'application/json' - }); - } - - function createSignupHint(data) { - return $.ajax({ - type: "POST", - url: '/api/signup_hints', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(data), - }); - } - - function createRedirectHint(data) { - return $.ajax({ - type: "POST", - url: '/api/redirect_hints', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(data), - }); - } - - function signup(data) { - return $.ajax({ - type: "POST", - url: '/api/users', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(data), - }); - } - - function redeemGiftCard(data) { - var id = getId(data); - return $.ajax({ - type: "POST", - url: '/api/users/' + id + '/gift_cards', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(data), - }); - } - - function portOverCarts() { - return $.ajax({ - type: "POST", - url: '/api/shopping_carts/port', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(data) + context.JK.GA.trackFriendConnect(context.JK.GA.FriendConnectTypes.request); + }, + error: app.ajaxError + }); + } + + function getFriendRequest(options) { + var id = getId(options); + var friendRequestId = options["friend_request_id"]; + + var deferred = $.ajax({ + type: "GET", + dataType: "json", + contentType: 'application/json', + url: "/api/users/" + id + "/friend_requests/" + friendRequestId, + processData: false + }); + + return deferred; + } + + function acceptFriendRequest(options) { + var id = getId(options); + var friendRequestId = options["friend_request_id"]; + var status = options["status"]; + + var friend_request = {status: status}; + + var deferred = $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/users/" + id + "/friend_requests/" + friendRequestId, + data: JSON.stringify(friend_request), + processData: false + }); + + deferred.done(function () { + context.JK.GA.trackFriendConnect(context.JK.GA.FriendConnectTypes.accept); + }); + + return deferred; + } + + function userDownloadedClient(options) { + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/users/progression/downloaded_client", + processData: false + }); + } + + function userCertifiedGear(options) { + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/users/progression/certified_gear", + processData: false, + data: JSON.stringify({ + success: options.success, + reason: options.reason }) - } - - - function attachRecordingToLesson(data) { - return $.ajax({ - type: "POST", - url: '/api/lesson_sessions/' + data.id + '/attach_recording', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(data) - }) - } - - - function bookLesson(data) { - return $.ajax({ - type: "POST", - url: '/api/lesson_bookings', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(data) - }) - } - - function getTestDrivePackageChoice(options) { - options = options || {} - return $.ajax({ - type: "GET", - url: '/api/test_drive_package_choice/' + options.id, - dataType: "json", - contentType: 'application/json' - }) - } - - function getLessonBooking(options) { - options = options || {} - return $.ajax({ - type: "GET", - url: '/api/lesson_bookings/' + options.id, - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options) - }) - } - - - function getUnprocessedLesson(options) { - options = options || {} - return $.ajax({ - type: "GET", - url: '/api/lesson_bookings/unprocessed', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options) - }) - } - - function getUnprocessedLessonOrIntent(options) { - options = options || {} - return $.ajax({ - type: "GET", - url: '/api/lesson_bookings/unprocessed_or_intent', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options) - }) - } - - function acceptLessonBooking(options) { - return $.ajax({ - type: "POST", - url: '/api/lesson_bookings/' + options.id + '/accept', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options) - }) - } - - function counterLessonBooking(options) { - return $.ajax({ - type: "POST", - url: '/api/lesson_bookings/' + options.id + '/counter', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options) - }) - } - - - function cancelLessonBooking(options) { - return $.ajax({ - type: "POST", - url: '/api/lesson_bookings/' + options.id + '/cancel', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options) - }) - } - - function createAlert(subject, data) { - var message = {subject:subject}; - $.extend(message, data); - console.log("message", message) - return $.ajax({ - type: "POST", - url: '/api/alerts', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(message), - }); - } - - function submitStripe(options) { - return $.ajax({ - type: "POST", - url: '/api/stripe', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options) - }) - } - - function getLessonSessions(options) { - options = options || {} - return $.ajax({ - type: "GET", - url: "/api/lesson_sessions?" + $.param(options), - dataType: "json", - contentType: 'application/json' - }); - } - - function getUncollectables(options) { - options = options || {} - return $.ajax({ - type: "GET", - url: "/api/lesson_sessions/uncollectable", - dataType: "json", - contentType: 'application/json' - }); - } - - - function getLesson(options) { - options = options || {} - return $.ajax({ - type: "GET", - url: "/api/lesson_sessions/" + options.id, - dataType: "json", - contentType: 'application/json' - }); - } - - function getLessonAnalysis(options) { - options = options || {} - return $.ajax({ - type: "GET", - url: "/api/lesson_sessions/" + options.id + "/analysis", - dataType: "json", - contentType: 'application/json' - }); - } - - - function updateLessonSessionUnreadMessages(options) { - return $.ajax({ - type: "POST", - url: '/api/lesson_sessions/' + options.id + "/update_unread_messages", - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options) - }) - } - - function checkLessonReschedule(options) { - return $.ajax({ - type: "POST", - url: '/api/lesson_sessions/' + options.id + "/reschedule_check", - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options) - }) - } - - - function checkLessonCancel(options) { - return $.ajax({ - type: "POST", - url: '/api/lesson_sessions/' + options.id + "/cancel_check", - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options) - }) - } - - function lessonStartTime(options) { - return $.ajax({ - type: "POST", - url: '/api/lesson_sessions/' + options.id + "/start_time", - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options) - }) - } - function getTestDriveStatus(options) { - return $.ajax({ - type: "GET", - url: "/api/users/" + options.id + "/test_drive/" + options.teacher_id, - dataType: "json", - contentType: 'application/json' - }); - } - - function createTeacherIntent(options) { - return $.ajax({ - type: "POST", - url: '/api/teachers/' + options.id + "/intent", - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options) - }) - } - - function getSchool(options) { - - var id = getId(options); - return $.ajax({ - type: "GET", - url: "/api/schools/" + id, - dataType: "json", - contentType: 'application/json' - }); - } - - function updateSchool(options) { - var id = getId(options); - return $.ajax({ - type: "POST", - url: '/api/schools/' + id, - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options) - }) - } - - function updateSchoolAvatar(options) { - var id = getId(options); - - var original_fpfile = options['original_fpfile']; - var cropped_fpfile = options['cropped_fpfile']; - var cropped_large_fpfile = options['cropped_large_fpfile']; - var crop_selection = options['crop_selection']; - - logger.debug(JSON.stringify({ - original_fpfile : original_fpfile, - cropped_fpfile : cropped_fpfile, - cropped_large_fpfile : cropped_large_fpfile, - crop_selection : crop_selection - })); - - var url = "/api/schools/" + id + "/avatar"; - return $.ajax({ - type: "POST", - dataType: "json", - url: url, - contentType: 'application/json', - processData:false, - data: JSON.stringify({ - original_fpfile : original_fpfile, - cropped_fpfile : cropped_fpfile, - cropped_large_fpfile : cropped_large_fpfile, - crop_selection : crop_selection - }) - }); - } - - function deleteSchoolAvatar(options) { - var id = getId(options); - - var url = "/api/schools/" + id + "/avatar"; - return $.ajax({ - type: "DELETE", - dataType: "json", - url: url, - contentType: 'application/json', - processData:false - }); - } - - function generateSchoolFilePickerPolicy(options) { - var id = getId(options); - var handle = options && options["handle"]; - var convert = options && options["convert"] - - var url = "/api/schools/" + id + "/filepicker_policy"; - - return $.ajax(url, { - data : { handle : handle, convert: convert }, - dataType : 'json' - }); - } - - function listSchoolInvitations(options) { - - var id = getId(options); - - return $.ajax({ - type: "GET", - url: "/api/schools/" + id + '/invitations?' + $.param(options) , - dataType: "json", - contentType: 'application/json' - }); - } - - function createSchoolInvitation(options) { - - var id = getId(options); - - return $.ajax({ - type: "POST", - url: "/api/schools/" + id + '/invitations?' + $.param(options) , - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options) - }); - } - - function deleteSchoolInvitation(options) { - - var id = getId(options); - - return $.ajax({ - type: "DELETE", - url: "/api/schools/" + id + '/invitations/' + options.invitation_id, - dataType: "json", - contentType: 'application/json' - }); - } - - function resendSchoolInvitation(options) { - - var id = getId(options); - - return $.ajax({ - type: "POST", - url: "/api/schools/" + id + '/invitations/' + options.invitation_id + '/resend', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options) - }); - } - - function deleteSchoolStudent(options) { - - var id = getId(options); - - return $.ajax({ - type: "DELETE", - url: "/api/schools/" + id + '/students/' + options.student_id, - dataType: "json", - contentType: 'application/json' - }); - } - - function deleteSchoolTeacher(options) { - - var id = getId(options); - - return $.ajax({ - type: "DELETE", - url: "/api/schools/" + id + '/teachers/' + options.teacher_id, - dataType: "json", - contentType: 'application/json' - }); - } - - function getRetailer(options) { - - var id = getId(options); - return $.ajax({ - type: "GET", - url: "/api/retailers/" + id, - dataType: "json", - contentType: 'application/json' - }); - } - - function updateRetailer(options) { - var id = getId(options); - return $.ajax({ - type: "POST", - url: '/api/retailers/' + id, - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options) - }) - } - - function updateRetailerAvatar(options) { - var id = getId(options); - - var original_fpfile = options['original_fpfile']; - var cropped_fpfile = options['cropped_fpfile']; - var cropped_large_fpfile = options['cropped_large_fpfile']; - var crop_selection = options['crop_selection']; - - logger.debug(JSON.stringify({ - original_fpfile : original_fpfile, - cropped_fpfile : cropped_fpfile, - cropped_large_fpfile : cropped_large_fpfile, - crop_selection : crop_selection - })); - - var url = "/api/retailers/" + id + "/avatar"; - return $.ajax({ - type: "POST", - dataType: "json", - url: url, - contentType: 'application/json', - processData:false, - data: JSON.stringify({ - original_fpfile : original_fpfile, - cropped_fpfile : cropped_fpfile, - cropped_large_fpfile : cropped_large_fpfile, - crop_selection : crop_selection - }) - }); - } - - function deleteRetailerAvatar(options) { - var id = getId(options); - - var url = "/api/retailers/" + id + "/avatar"; - return $.ajax({ - type: "DELETE", - dataType: "json", - url: url, - contentType: 'application/json', - processData:false - }); - } - - function generateRetailerFilePickerPolicy(options) { - var id = getId(options); - var handle = options && options["handle"]; - var convert = options && options["convert"] - - var url = "/api/retailers/" + id + "/filepicker_policy"; - - return $.ajax(url, { - data : { handle : handle, convert: convert }, - dataType : 'json' - }); - } - - function listRetailerInvitations(options) { - - var id = getId(options); - - return $.ajax({ - type: "GET", - url: "/api/retailers/" + id + '/invitations?' + $.param(options) , - dataType: "json", - contentType: 'application/json' - }); - } - - function createRetailerInvitation(options) { - - var id = getId(options); - - return $.ajax({ - type: "POST", - url: "/api/retailers/" + id + '/invitations?' + $.param(options) , - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options) - }); - } - - function deleteRetailerInvitation(options) { - - var id = getId(options); - - return $.ajax({ - type: "DELETE", - url: "/api/retailers/" + id + '/invitations/' + options.invitation_id, - dataType: "json", - contentType: 'application/json' - }); - } - - function resendRetailerInvitation(options) { - - var id = getId(options); - - return $.ajax({ - type: "POST", - url: "/api/retaiers/" + id + '/invitations/' + options.invitation_id + '/resend', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options) - }); - } - - function deleteRetailerStudent(options) { - - var id = getId(options); - - return $.ajax({ - type: "DELETE", - url: "/api/retailers/" + id + '/students/' + options.student_id, - dataType: "json", - contentType: 'application/json' - }); - } - - function deleteRetailerTeacher(options) { - - var id = getId(options); - - return $.ajax({ - type: "DELETE", - url: "/api/retailers/" + id + '/teachers/' + options.teacher_id, - dataType: "json", - contentType: 'application/json' - }); - } - - function listTeacherDistributions(options) { - - if(!options) { - options = {} - } - - return $.ajax({ - type: "GET", - url: "/api/teacher_distributions?" + $.param(options) , - dataType: "json", - contentType: 'application/json' - }); - } - - function createReview(options) { - - return $.ajax({ - type: "POST", - url: '/api/reviews', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options), - }); - } - - function askSearchHelp(options) { - - return $.ajax({ - type: "POST", - url: '/api/teachers/search_help', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options), - }) - } - - function ratingDecision(options) { - return $.ajax({ - type: "GET", - url: '/api/lesson_sessions/rating_decision?' + $.param(options), - dataType: "json", - contentType: 'application/json' - }) - } - - function posaActivate(options) { - var slug = options.slug - delete options.slug - - return $.ajax({ - type: "POST", - url: '/api/posa/' + slug + '/activate', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options), - }) - } - - function posaClaim(options) { - - return $.ajax({ - type: "POST", - url: '/api/posa/claim', - dataType: "json", - contentType: 'application/json', - data: JSON.stringify(options), - }) - } - - function sendRetailerCustomerEmail(options) { - options = options || {} - var retailerId = options.retailer - delete options.retailer - - return $.ajax({ - type: 'POST', - url: '/api/retailers/' + retailerId + '/customer_email', - dataType: 'json', - contentType: 'application/json', - data: JSON.stringify(options) - }) - } - - function paypalDetail(options) { - options = options || {} - return $.ajax({ - type: 'POST', - url: '/api/paypal/checkout/detail', - dataType: 'json', - contentType: 'application/json', - data: JSON.stringify(options) - }) - } - - function paypalPlaceOrder(options) { - options = options || {} - return $.ajax({ - type: 'POST', - url: '/api/paypal/checkout/confirm', - dataType: 'json', - contentType: 'application/json', - data: JSON.stringify(options) - }) - } - - function initialize() { - return self; - } - - // Expose publics - this.initialize = initialize; - this.legacyCreateSession = legacyCreateSession; - this.createScheduledSession = createScheduledSession; - this.uploadMusicNotations = uploadMusicNotations; - this.getMusicNotation = getMusicNotation; - this.deleteMusicNotation = deleteMusicNotation; - this.getBroadcastNotification = getBroadcastNotification; - this.quietBroadcastNotification = quietBroadcastNotification; - this.legacyJoinSession = legacyJoinSession; - this.joinSession = joinSession; - this.cancelSession = cancelSession; - this.updateScheduledSession = updateScheduledSession; - this.getUserDetail = getUserDetail; - this.getUserJamBlasters = getUserJamBlasters; - this.getUserAuthorizations = getUserAuthorizations; - this.getGoogleAuth = getGoogleAuth; - this.getUserProfile = getUserProfile; - this.getAffiliatePartnerData = getAffiliatePartnerData; - this.postAffiliatePartnerData = postAffiliatePartnerData; - this.createAffiliatePartner = createAffiliatePartner; - this.getLinks = getLinks; - this.getAffiliateSignups = getAffiliateSignups; - this.getAffiliateMonthly = getAffiliateMonthly; - this.getAffiliateQuarterly = getAffiliateQuarterly; - this.getAffiliatePayments = getAffiliatePayments; - this.getCities = getCities; - this.getRegions = getRegions; - this.getCountries = getCountries; - this.getResolvedLocation = getResolvedLocation; - this.getInstruments = getInstruments; - this.getGenres = getGenres; - this.getSubjects = getSubjects; - this.getLanguages = getLanguages; - this.updateUdpReachable = updateUdpReachable; - this.updateNetworkTesting = updateNetworkTesting; - this.updateAvatar = updateAvatar; - this.deleteAvatar = deleteAvatar; - this.getFilepickerPolicy = getFilepickerPolicy; - this.getFriends = getFriends; - this.removeFriend = removeFriend; - this.addLike = addLike; - this.removeLike = removeLike; - this.addFollowing = addFollowing; - this.removeFollowing = removeFollowing; - this.getFollowings = getFollowings; - this.getFollowers = getFollowers; - this.getBands = getBands; - this.getBandFollowers = getBandFollowers; - this.findActiveSessions = findActiveSessions; - this.findInactiveSessions = findInactiveSessions; - this.findScheduledSessions = findScheduledSessions; - this.findScheduledRsvpSessions = findScheduledRsvpSessions; - this.updateSession = updateSession; - this.getSessionHistory = getSessionHistory; - this.addSessionComment = addSessionComment; - this.addSessionInfoComment = addSessionInfoComment; - this.addSessionLike = addSessionLike; - this.getRsvpRequests = getRsvpRequests; - this.submitRsvpRequest = submitRsvpRequest; - this.updateRsvpRequest = updateRsvpRequest; - this.cancelRsvpRequest = cancelRsvpRequest; - this.getOpenSessionSlots = getOpenSessionSlots; - this.addRecordingComment = addRecordingComment; - this.addRecordingLike = addRecordingLike; - this.addPlayablePlay = addPlayablePlay; - this.getSession = getSession; - this.deleteParticipant = deleteParticipant; - this.getClientDownloads = getClientDownloads; - this.createEmailInvitations = createEmailInvitations; - this.createMusicianInvite = createMusicianInvite; - this.getMusicianInvites = getMusicianInvites; - this.postFeedback = postFeedback; - this.getFeeds = getFeeds; - this.getUserSyncs = getUserSyncs; - this.getUserSync = getUserSync; - this.serverHealthCheck = serverHealthCheck; - this.sendFriendRequest = sendFriendRequest; - this.getFriendRequest = getFriendRequest; - this.acceptFriendRequest = acceptFriendRequest; - this.signout = signout; - this.userDownloadedClient = userDownloadedClient; - this.userCertifiedGear = userCertifiedGear; - this.userSocialPromoted = userSocialPromoted; - this.userOpenedJamTrackWebPlayer = userOpenedJamTrackWebPlayer; - this.postUserEvent = postUserEvent; - this.createJoinRequest = createJoinRequest; - this.updateJoinRequest = updateJoinRequest; - this.updateUser = updateUser; - this.startRecording = startRecording; - this.stopRecording = stopRecording; - this.getRecording = getRecording; - this.getRecordedTrack = getRecordedTrack; - this.getRecordedBackingTrack = getRecordedBackingTrack; - this.getClaimedRecordings = getClaimedRecordings; - this.getClaimedRecording = getClaimedRecording; - this.updateClaimedRecording = updateClaimedRecording; - this.deleteClaimedRecording = deleteClaimedRecording; - this.deleteRecordingClaim = deleteRecordingClaim; - this.claimRecording = claimRecording; - this.startPlayClaimedRecording = startPlayClaimedRecording; - this.stopPlayClaimedRecording = stopPlayClaimedRecording; - this.markMixdownActive = markMixdownActive; - this.createMixdown = createMixdown; - this.editMixdown = editMixdown; - this.deleteMixdown = deleteMixdown; - this.enqueueMixdown = enqueueMixdown; - this.getMixdown = getMixdown; - this.getMixdownPackage = getMixdownPackage; - this.openJamTrack = openJamTrack - this.openBackingTrack = openBackingTrack - this.closeBackingTrack = closeBackingTrack - this.closeMetronome = closeMetronome; - this.closeJamTrack = closeJamTrack; - this.openMetronome = openMetronome; - this.closeMetronome = closeMetronome; - this.discardRecording = discardRecording; - this.putTrackSyncChange = putTrackSyncChange; - this.createBand = createBand; - this.updateBand = updateBand; - this.updateBandPhoto = updateBandPhoto; - this.deleteBandPhoto = deleteBandPhoto; - this.deleteBand = deleteBand; - this.getBandPhotoFilepickerPolicy = getBandPhotoFilepickerPolicy; - this.getBand = getBand; - this.validateBand = validateBand; - this.getTeacher = getTeacher; - this.updateTeacher = updateTeacher; - this.deleteTeacher = deleteTeacher; - this.updateFavorite = updateFavorite; - this.createBandInvitation = createBandInvitation; - this.updateBandInvitation = updateBandInvitation; - this.removeBandMember = removeBandMember; - this.getBandMembers = getBandMembers; - this.login = login; - this.getShareSession = getShareSession; - this.getShareRecording = getShareRecording; - this.tweet = tweet; - this.createFbInviteUrl = createFbInviteUrl; - this.createTextMessage = createTextMessage; - this.getTextMessages = getTextMessages; - this.getNotifications = getNotifications; - this.createChatMessage = createChatMessage; - this.getChatMessages = getChatMessages; - this.createDiagnostic = createDiagnostic; - this.getLatencyTester = getLatencyTester; - this.updateAudioLatency = updateAudioLatency; - this.getJamTrack = getJamTrack; - this.getJamTrackWithArtistInfo = getJamTrackWithArtistInfo; - this.getJamTracks = getJamTracks; - this.autocompleteJamTracks = autocompleteJamTracks; - this.getJamTrackArtists = getJamTrackArtists; - this.getPurchasedJamTracks = getPurchasedJamTracks; - this.getPaymentHistory = getPaymentHistory; - this.getSalesHistory = getSalesHistory; - this.getJamTrackRight = getJamTrackRight; - this.enqueueJamTrack = enqueueJamTrack; - this.getBackingTracks = getBackingTracks; - this.addJamtrackToShoppingCart = addJamtrackToShoppingCart; - this.addGiftCardToShoppingCart = addGiftCardToShoppingCart; - this.getShoppingCarts = getShoppingCarts; - this.removeShoppingCart = removeShoppingCart; - this.clearShoppingCart = clearShoppingCart; - this.getRecurlyAccount = getRecurlyAccount; - this.createRecurlyAccount = createRecurlyAccount; - this.getBillingInfo = getBillingInfo; - this.updateBillingInfo = updateBillingInfo; - this.placeOrder = placeOrder; - this.searchMusicians = searchMusicians; - this.searchTeachers = searchTeachers; - this.resendBandInvitation = resendBandInvitation; - this.getMount = getMount; - this.createSourceChange = createSourceChange; - this.validateUrlSite = validateUrlSite; - this.markRecordedBackingTrackSilent = markRecordedBackingTrackSilent; - this.addRecordingTimeline = addRecordingTimeline; - this.addRecordingVideoData = addRecordingVideoData; - this.deleteRecordingVideoData = deleteRecordingVideoData; - this.getMusicianSearchFilter = getMusicianSearchFilter; - this.postMusicianSearchFilter = postMusicianSearchFilter; - this.getBandSearchFilter = getBandSearchFilter; - this.postBandSearchFilter = postBandSearchFilter; - this.playJamTrack = playJamTrack; - this.createSignupHint = createSignupHint; - this.createRedirectHint = createRedirectHint; - this.createAlert = createAlert; - this.redeemGiftCard = redeemGiftCard; - this.signup = signup; - this.portOverCarts = portOverCarts; - this.bookLesson = bookLesson; - this.attachRecordingToLesson = attachRecordingToLesson; - this.getTestDrivePackageChoice = getTestDrivePackageChoice; - this.getLessonBooking = getLessonBooking; - this.getUnprocessedLesson = getUnprocessedLesson; - this.getUnprocessedLessonOrIntent = getUnprocessedLessonOrIntent; - this.acceptLessonBooking = acceptLessonBooking; - this.cancelLessonBooking = cancelLessonBooking; - this.counterLessonBooking = counterLessonBooking; - this.submitStripe = submitStripe; - this.getLessonSessions = getLessonSessions; - this.getUncollectables = getUncollectables; - this.getLesson = getLesson; - this.getLessonAnalysis = getLessonAnalysis; - this.updateLessonSessionUnreadMessages = updateLessonSessionUnreadMessages; - this.checkLessonCancel = checkLessonCancel; - this.checkLessonReschedule = checkLessonReschedule; - this.getTestDriveStatus = getTestDriveStatus; - this.createTeacherIntent = createTeacherIntent; - this.getSchool = getSchool; - this.updateSchool = updateSchool; - this.updateSchoolAvatar = updateSchoolAvatar; - this.deleteSchoolAvatar = deleteSchoolAvatar; - this.generateSchoolFilePickerPolicy = generateSchoolFilePickerPolicy; - this.listSchoolInvitations = listSchoolInvitations; - this.createSchoolInvitation = createSchoolInvitation; - this.deleteSchoolInvitation = deleteSchoolInvitation; - this.resendSchoolInvitation = resendSchoolInvitation; - this.deleteSchoolTeacher = deleteSchoolTeacher; - this.deleteSchoolStudent = deleteSchoolStudent; - this.getRetailer = getRetailer; - this.updateRetailer = updateRetailer; - this.updateRetailerAvatar = updateRetailerAvatar; - this.deleteRetailerAvatar = deleteRetailerAvatar; - this.generateRetailerFilePickerPolicy = generateRetailerFilePickerPolicy; - this.listRetailerInvitations = listRetailerInvitations; - this.createRetailerInvitation = createRetailerInvitation; - this.deleteRetailerInvitation = deleteRetailerInvitation; - this.resendRetailerInvitation = resendRetailerInvitation; - this.deleteRetailerTeacher = deleteRetailerTeacher; - this.deleteRetailerStudent = deleteRetailerStudent; - this.listTeacherDistributions = listTeacherDistributions; - this.lessonStartTime = lessonStartTime; - this.createReview = createReview; - this.askSearchHelp = askSearchHelp; - this.ratingDecision = ratingDecision; - this.posaActivate = posaActivate; - this.posaClaim = posaClaim; - this.sendRetailerCustomerEmail = sendRetailerCustomerEmail; - this.paypalDetail = paypalDetail; - this.paypalPlaceOrder = paypalPlaceOrder; - return this; + }); + } + + function userSocialPromoted(options) { + var id = getId(options); + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/users/progression/social_promoted", + processData: false + }); + } + + function userOpenedJamTrackWebPlayer(options) { + var id = getId(options); + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/users/progression/opened_jamtrack_web_player", + processData: false + }); + } + + function postUserEvent(options) { + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/users/event/record", + data: JSON.stringify(options), + processData: false + }); + } + + function signout() { + return $.ajax({ + type: "DELETE", + dataType: "json", + url: '/signout', + contentType: 'application/json' + }); + } + + function updateUser(options) { + options = options || {}; + var id = getId(options); + + delete options['id']; + + var deferred = $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/users/" + id, + data: JSON.stringify(options), + processData: false + }); + + deferred.done(function (user) { + context.JK.currentUserFreeJamTrack = user.show_free_jamtrack + window.UserActions.loaded(user) + }) + + return deferred; + + } + + function startRecording(options) { + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/recordings/start", + data: JSON.stringify(options) + }) + } + + function stopRecording(options) { + var recordingId = options["id"] + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/recordings/" + recordingId + "/stop", + data: JSON.stringify(options) + }) + } + + function markRecordedBackingTrackSilent(options) { + var recordingId = options["recording_id"]; + var trackId = options["backing_track_id"]; + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + data: {}, + url: "/api/recordings/" + recordingId + "/backing_tracks/" + trackId + '/silent' + }); + } + + function getRecordedTrack(options) { + var recordingId = options["recording_id"]; + var trackId = options["track_id"]; + + return $.ajax({ + type: "GET", + dataType: "json", + contentType: 'application/json', + url: "/api/recordings/" + recordingId + "/tracks/" + trackId + }); + } + + function getRecordedBackingTrack(options) { + var recordingId = options["recording_id"]; + var trackId = options["track_id"]; + + return $.ajax({ + type: "GET", + dataType: "json", + contentType: 'application/json', + url: "/api/recordings/" + recordingId + "/backing_tracks/" + trackId + }); + } + + function getRecording(options) { + var recordingId = options["id"]; + + return $.ajax({ + type: "GET", + dataType: "json", + contentType: 'application/json', + url: "/api/recordings/" + recordingId + }); + } + + function getClaimedRecordings(options) { + return $.ajax({ + type: "GET", + dataType: "json", + contentType: 'application/json', + url: "/api/claimed_recordings", + data: options + }); + } + + function getClaimedRecording(id) { + return $.ajax({ + type: "GET", + dataType: "json", + contentType: 'application/json', + url: "/api/claimed_recordings/" + id + }); + } + + function updateClaimedRecording(options) { + var claimedRecordingId = options["id"]; + return $.ajax({ + type: "PUT", + dataType: "json", + url: '/api/claimed_recordings/' + claimedRecordingId, + contentType: 'application/json', + processData: false, + data: JSON.stringify(options) + }); + } + + function deleteClaimedRecording(id) { + return $.ajax({ + type: "DELETE", + dataType: "json", + contentType: 'application/json', + url: "/api/claimed_recordings/" + id + }); + } + + function deleteRecordingClaim(id) { + return $.ajax({ + type: "DELETE", + dataType: "json", + contentType: 'application/json', + url: "/api/recordings/" + id + "/claim" + }); + } + + function claimRecording(options) { + var recordingId = options["id"]; + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/recordings/" + recordingId + "/claim", + data: JSON.stringify(options) + }) + } + + function startPlayClaimedRecording(options) { + var musicSessionId = options["id"]; + var claimedRecordingId = options["claimed_recording_id"]; + delete options["id"]; + delete options["claimed_recording_id"]; + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/sessions/" + musicSessionId + "/claimed_recording/" + claimedRecordingId + "/start", + data: JSON.stringify(options) + }) + } + + function stopPlayClaimedRecording(options) { + var musicSessionId = options["id"]; + var claimedRecordingId = options["claimed_recording_id"]; + delete options["id"]; + delete options["claimed_recording_id"]; + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/sessions/" + musicSessionId + "/claimed_recording/" + claimedRecordingId + "/stop", + data: JSON.stringify(options) + }) + } + + function openBackingTrack(options) { + var musicSessionId = options["id"]; + delete options["id"]; + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/sessions/" + musicSessionId + "/backing_tracks/open", + data: JSON.stringify(options) + }) + } + + function closeBackingTrack(options) { + var musicSessionId = options["id"]; + delete options["id"]; + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/sessions/" + musicSessionId + "/backing_tracks/close", + data: JSON.stringify(options) + }) + } + + function markMixdownActive(options) { + var id = options["id"]; + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/jamtracks/" + id + "/mixdowns/active", + data: JSON.stringify(options) + }) + } + + function createMixdown(options) { + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/mixdowns/", + data: JSON.stringify(options) + }) + } + + function editMixdown(options) { + var id = options["id"]; + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/mixdowns/" + id, + data: JSON.stringify(options) + }) + } + + function deleteMixdown(options) { + var id = options["id"]; + + return $.ajax({ + type: "DELETE", + dataType: "json", + contentType: 'application/json', + url: "/api/mixdowns/" + id + }) + } + + function getMixdown(options) { + var id = options["id"]; + + return $.ajax({ + type: "GET", + dataType: "json", + contentType: 'application/json', + url: "/api/mixdowns/" + id + }) + } + + function getMixdownPackage(options) { + var id = options["id"]; + + return $.ajax({ + type: "GET", + dataType: "json", + contentType: 'application/json', + url: "/api/mixdown_packages/" + id + }) + } + + function enqueueMixdown(options) { + var id = options["id"]; + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/mixdowns/" + id + '/enqueue', + data: JSON.stringify(options) + }) + } + + function openJamTrack(options) { + var musicSessionId = options["id"]; + var jamTrackId = options["jam_track_id"]; + delete options["id"]; + delete options["jam_track_id"]; + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/sessions/" + musicSessionId + "/jam_tracks/" + jamTrackId + "/open", + data: JSON.stringify(options) + }) + } + + function playJamTrack(jamTrackId) { + return $.ajax({ + type: "POST", + url: '/api/jamtracks/played/' + jamTrackId, + dataType: "json", + contentType: 'application/json' + }); + } + + function closeJamTrack(options) { + var musicSessionId = options["id"]; + delete options["id"]; + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/sessions/" + musicSessionId + "/jam_tracks/close", + data: JSON.stringify(options) + }) + } + + function openMetronome(options) { + var musicSessionId = options["id"]; + delete options["id"]; + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/sessions/" + musicSessionId + "/metronome/open", + data: JSON.stringify(options) + }) + } + + function closeMetronome(options) { + var musicSessionId = options["id"]; + delete options["id"]; + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/sessions/" + musicSessionId + "/metronome/close", + data: JSON.stringify(options) + }) + } + + function discardRecording(options) { + var recordingId = options["id"]; + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/recordings/" + recordingId + "/discard", + data: JSON.stringify(options) + }) + } + + function putTrackSyncChange(options) { + var musicSessionId = options["id"] + delete options["id"]; + + return $.ajax({ + type: "PUT", + dataType: "json", + url: '/api/sessions/' + musicSessionId + '/tracks', + contentType: 'application/json', + processData: false, + data: JSON.stringify(options) + }); + } + + function getShareSession(options) { + var id = getId(options); + var provider = options['provider']; + delete options['provider'] + + return $.ajax({ + type: "GET", + dataType: "json", + contentType: 'application/json', + url: "/api/users/" + id + "/share/session/" + provider, + data: options + }) + } + + function getShareRecording(options) { + var id = getId(options); + var provider = options['provider']; + delete options['provider'] + + return $.ajax({ + type: "GET", + dataType: "json", + contentType: 'application/json', + url: "/api/users/" + id + "/share/recording/" + provider, + data: options + }) + } + + function tweet(options) { + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/twitter/tweet", + data: JSON.stringify(options) + }) + } + + function createFbInviteUrl() { + return $.ajax({ + type: "GET", + url: '/api/invited_users/facebook', + dataType: "json", + contentType: 'application/json' + }); + } + + function createTextMessage(options) { + var id = getId(options); + return $.ajax({ + type: "POST", + url: '/api/text_messages', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }); + } + + function getTextMessages(options) { + if (!options) options = {}; + var id = getId(options); + return $.ajax({ + type: "GET", + url: '/api/text_messages?' + $.param(options), + dataType: "json", + contentType: 'application/json' + }); + } + + function getNotifications(options) { + if (!options) options = {}; + var id = getId(options); + return $.ajax({ + type: "GET", + url: '/api/users/' + id + '/notifications?' + $.param(options), + dataType: "json", + contentType: 'application/json' + }); + } + + function createChatMessage(data) { + return $.ajax({ + type: "POST", + url: '/api/chat', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(data) + }); + } + + function getChatMessages(options) { + return $.ajax({ + type: "GET", + url: '/api/chat?' + $.param(options), + dataType: "json", + contentType: 'application/json' + }) }; -})(window,jQuery); + + function createDiagnostic(options) { + var data = null; + try { + data = JSON.stringify(options) + } + catch (e) { + data = JSON.stringify({data_error: "unable to JSON.stringify debug data:" + e.toString()}) + } + return $.ajax({ + type: "POST", + url: '/api/diagnostics', + dataType: "json", + contentType: 'application/json', + data: data, + }); + } + + function getLatencyTester(options) { + return $.ajax({ + type: "GET", + url: '/api/latency_testers', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }); + } + + function updateAudioLatency(options) { + var id = getId(options); + return $.ajax({ + type: "POST", + url: '/api/users/' + id + '/audio_latency', + dataType: "json", + contentType: 'application/json', + data: options, + }); + } + + function getJamTrack(options) { + return $.ajax({ + type: "GET", + url: '/api/jamtracks/' + options['plan_code'] + '?' + $.param(options), + dataType: "json", + contentType: 'application/json' + }); + } + + function getJamTrackWithArtistInfo(options) { + return $.ajax({ + type: "GET", + url: '/api/jamtracks/band/' + options['plan_code'] + '?' + $.param(options), + dataType: "json", + contentType: 'application/json' + }); + } + + function getJamTracks(options) { + return $.ajax({ + type: "GET", + url: '/api/jamtracks?' + $.param(options), + dataType: "json", + contentType: 'application/json' + }); + } + + function autocompleteJamTracks(options) { + return $.ajax({ + type: "GET", + url: '/api/jamtracks/autocomplete?' + $.param(options), + dataType: "json", + contentType: 'application/json' + }); + } + + function getJamTrackArtists(options) { + return $.ajax({ + type: "GET", + url: '/api/jamtracks/artists?' + $.param(options), + dataType: "json", + contentType: 'application/json' + }); + } + + function getJamTrackRight(options) { + var jamTrackId = options['id']; + + return $.ajax({ + type: "GET", + url: '/api/jamtracks/rights/' + jamTrackId + '?' + $.param(options), + dataType: "json", + contentType: 'application/json' + }) + } + + function enqueueJamTrack(options) { + var jamTrackId = options['id']; + delete options['id'] + + return $.ajax({ + type: "POST", + url: '/api/jamtracks/enqueue/' + jamTrackId, + dataType: "json", + data: options + }); + } + + function getPurchasedJamTracks(options) { + return $.ajax({ + type: "GET", + url: '/api/jamtracks/purchased?' + $.param(options), + dataType: "json", + contentType: 'application/json' + }); + } + + function getPaymentHistory(options) { + return $.ajax({ + type: "GET", + url: '/api/recurly/payment_history', + dataType: "json", + contentType: 'application/json' + }); + } + + function getSalesHistory(options) { + return $.ajax({ + type: "GET", + url: '/api/payment_histories?' + $.param(options), + dataType: "json", + contentType: 'application/json' + }); + } + + function getBackingTracks(options) { + return $.ajax({ + type: "GET", + url: '/api/backing_tracks?' + $.param(options), + dataType: "json", + contentType: 'application/json' + }); + } + + function addJamtrackToShoppingCart(options) { + var deferred = $.ajax({ + type: "POST", + url: '/api/shopping_carts/add_jamtrack?' + $.param(options), + dataType: "json", + contentType: 'application/json' + }); + + deferred.done(function (response) { + window.UserActions.modify(response) + }) + return deferred + } + + function addGiftCardToShoppingCart(options) { + var deferred = $.ajax({ + type: "POST", + url: '/api/shopping_carts/add_gift_card?' + $.param(options), + dataType: "json", + contentType: 'application/json' + }); + + return deferred + } + + function getShoppingCarts() { + // the need for the time de-duplicator indicates we are doing something wrong on the server + return $.ajax({ + type: "GET", + url: '/api/shopping_carts?time=' + new Date().getTime(), + dataType: "json", + contentType: 'application/json' + }); + } + + function removeShoppingCart(options) { + var deferred = $.ajax({ + type: "DELETE", + url: '/api/shopping_carts?' + $.param(options), + dataType: "json", + contentType: 'application/json' + }) + + deferred.done(function (response) { + window.UserActions.modify(response) + }) + return deferred + } + + function clearShoppingCart(options) { + return $.ajax({ + type: "DELETE", + url: '/api/shopping_carts/clear_all', + dataType: "json", + contentType: 'application/json' + }) + } + + function getRecurlyAccount() { + return $.ajax({ + type: "GET", + url: '/api/recurly/get_account', + dataType: "json", + contentType: 'application/json' + }); + } + + function createRecurlyAccount(options) { + return $.ajax({ + type: "POST", + url: '/api/recurly/create_account?' + $.param(options), + dataType: "json", + contentType: 'application/json' + }); + } + + function getBillingInfo() { + return $.ajax({ + type: "GET", + url: '/api/recurly/billing_info', + dataType: "json", + contentType: 'application/json' + }); + } + + function updateBillingInfo(options) { + return $.ajax({ + type: "PUT", + url: '/api/recurly/update_billing_info?' + $.param({billing_info: options}), + dataType: "json", + //data: JSON.stringify({"billing_info": $.param(options)}), + contentType: 'application/json' + }); + } + + function placeOrder() { + return $.ajax({ + type: "POST", + url: '/api/recurly/place_order', + dataType: "json", + contentType: 'application/json' + }); + } + + function searchMusicians(query) { + return $.ajax({ + type: "GET", + url: "/api/search.json?" + $.param(query) + }); + } + + function searchTeachers(query) { + return $.ajax({ + type: "GET", + url: "/api/teachers?" + $.param(query), + dataType: "json", + contentType: 'application/json' + }); + } + + function getMusicianSearchFilter(query) { + var qarg = query === undefined ? '' : query; + return $.get("/api/search/musicians.json?" + qarg); + } + + function postMusicianSearchFilter(query) { + return $.ajax({ + type: "POST", + url: "/api/search/musicians.json", + data: query + }); + } + + function getBandSearchFilter(query) { + var qarg = query === undefined ? '' : query; + return $.get("/api/search/bands.json?" + qarg); + } + + function postBandSearchFilter(query) { + return $.ajax({ + type: "POST", + url: "/api/search/bands.json", + data: query + }); + } + + function getMount(options) { + var id = getId(options); + return $.ajax({ + type: "GET", + url: '/api/icecast/mount/' + id, + dataType: "json", + contentType: 'application/json' + }); + } + + function createSourceChange(options) { + var mountId = options['mount_id']; + + return $.ajax({ + type: "POST", + url: '/api/icecast/mount/' + mountId + '/source_change', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options), + }); + } + + function validateUrlSite(url, sitetype) { + return $.ajax({ + type: "GET", + url: '/api/data_validation?sitetype=' + sitetype + '&data=' + encodeURIComponent(url), + contentType: 'application/json' + }); + } + + function addRecordingTimeline(recordingId, data) { + return $.ajax({ + type: "POST", + url: '/api/recordings/' + recordingId + '/timeline', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(data), + }); + } + + + function addRecordingVideoData(recordingId, data) { + return $.ajax({ + type: "POST", + url: '/api/recordings/' + recordingId + '/video_data', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(data), + }); + } + + function deleteRecordingVideoData(recordingId) { + return $.ajax({ + type: "DELETE", + url: '/api/recordings/' + recordingId + '/video_data', + dataType: "json", + contentType: 'application/json' + }); + } + + function createSignupHint(data) { + return $.ajax({ + type: "POST", + url: '/api/signup_hints', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(data), + }); + } + + function createRedirectHint(data) { + return $.ajax({ + type: "POST", + url: '/api/redirect_hints', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(data), + }); + } + + function signup(data) { + return $.ajax({ + type: "POST", + url: '/api/users', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(data), + }); + } + + function redeemGiftCard(data) { + var id = getId(data); + return $.ajax({ + type: "POST", + url: '/api/users/' + id + '/gift_cards', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(data), + }); + } + + function portOverCarts() { + return $.ajax({ + type: "POST", + url: '/api/shopping_carts/port', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(data) + }) + } + + + function attachRecordingToLesson(data) { + return $.ajax({ + type: "POST", + url: '/api/lesson_sessions/' + data.id + '/attach_recording', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(data) + }) + } + + + function bookLesson(data) { + return $.ajax({ + type: "POST", + url: '/api/lesson_bookings', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(data) + }) + } + + function getTestDrivePackageChoice(options) { + options = options || {} + return $.ajax({ + type: "GET", + url: '/api/test_drive_package_choice/' + options.id, + dataType: "json", + contentType: 'application/json' + }) + } + + function getLessonBooking(options) { + options = options || {} + return $.ajax({ + type: "GET", + url: '/api/lesson_bookings/' + options.id, + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + + function getUnprocessedLesson(options) { + options = options || {} + return $.ajax({ + type: "GET", + url: '/api/lesson_bookings/unprocessed', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + function getUnprocessedLessonOrIntent(options) { + options = options || {} + return $.ajax({ + type: "GET", + url: '/api/lesson_bookings/unprocessed_or_intent', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + function acceptLessonBooking(options) { + return $.ajax({ + type: "POST", + url: '/api/lesson_bookings/' + options.id + '/accept', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + function counterLessonBooking(options) { + return $.ajax({ + type: "POST", + url: '/api/lesson_bookings/' + options.id + '/counter', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + + function cancelLessonBooking(options) { + return $.ajax({ + type: "POST", + url: '/api/lesson_bookings/' + options.id + '/cancel', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + function createAlert(subject, data) { + var message = {subject: subject}; + $.extend(message, data); + console.log("message", message) + return $.ajax({ + type: "POST", + url: '/api/alerts', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(message), + }); + } + + function submitStripe(options) { + return $.ajax({ + type: "POST", + url: '/api/stripe', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + function getLessonSessions(options) { + options = options || {} + return $.ajax({ + type: "GET", + url: "/api/lesson_sessions?" + $.param(options), + dataType: "json", + contentType: 'application/json' + }); + } + + function getUncollectables(options) { + options = options || {} + return $.ajax({ + type: "GET", + url: "/api/lesson_sessions/uncollectable", + dataType: "json", + contentType: 'application/json' + }); + } + + + function getLesson(options) { + options = options || {} + return $.ajax({ + type: "GET", + url: "/api/lesson_sessions/" + options.id, + dataType: "json", + contentType: 'application/json' + }); + } + + function getLessonAnalysis(options) { + options = options || {} + return $.ajax({ + type: "GET", + url: "/api/lesson_sessions/" + options.id + "/analysis", + dataType: "json", + contentType: 'application/json' + }); + } + + + function updateLessonSessionUnreadMessages(options) { + return $.ajax({ + type: "POST", + url: '/api/lesson_sessions/' + options.id + "/update_unread_messages", + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + function checkLessonReschedule(options) { + return $.ajax({ + type: "POST", + url: '/api/lesson_sessions/' + options.id + "/reschedule_check", + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + + function checkLessonCancel(options) { + return $.ajax({ + type: "POST", + url: '/api/lesson_sessions/' + options.id + "/cancel_check", + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + function lessonStartTime(options) { + return $.ajax({ + type: "POST", + url: '/api/lesson_sessions/' + options.id + "/start_time", + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + function getTestDriveStatus(options) { + return $.ajax({ + type: "GET", + url: "/api/users/" + options.id + "/test_drive/" + options.teacher_id, + dataType: "json", + contentType: 'application/json' + }); + } + + function createTeacherIntent(options) { + return $.ajax({ + type: "POST", + url: '/api/teachers/' + options.id + "/intent", + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + function getSchool(options) { + + var id = getId(options); + return $.ajax({ + type: "GET", + url: "/api/schools/" + id, + dataType: "json", + contentType: 'application/json' + }); + } + + function updateSchool(options) { + var id = getId(options); + return $.ajax({ + type: "POST", + url: '/api/schools/' + id, + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + function updateSchoolAvatar(options) { + var id = getId(options); + + var original_fpfile = options['original_fpfile']; + var cropped_fpfile = options['cropped_fpfile']; + var cropped_large_fpfile = options['cropped_large_fpfile']; + var crop_selection = options['crop_selection']; + + logger.debug(JSON.stringify({ + original_fpfile: original_fpfile, + cropped_fpfile: cropped_fpfile, + cropped_large_fpfile: cropped_large_fpfile, + crop_selection: crop_selection + })); + + var url = "/api/schools/" + id + "/avatar"; + return $.ajax({ + type: "POST", + dataType: "json", + url: url, + contentType: 'application/json', + processData: false, + data: JSON.stringify({ + original_fpfile: original_fpfile, + cropped_fpfile: cropped_fpfile, + cropped_large_fpfile: cropped_large_fpfile, + crop_selection: crop_selection + }) + }); + } + + function deleteSchoolAvatar(options) { + var id = getId(options); + + var url = "/api/schools/" + id + "/avatar"; + return $.ajax({ + type: "DELETE", + dataType: "json", + url: url, + contentType: 'application/json', + processData: false + }); + } + + function generateSchoolFilePickerPolicy(options) { + var id = getId(options); + var handle = options && options["handle"]; + var convert = options && options["convert"] + + var url = "/api/schools/" + id + "/filepicker_policy"; + + return $.ajax(url, { + data: {handle: handle, convert: convert}, + dataType: 'json' + }); + } + + function listSchoolInvitations(options) { + + var id = getId(options); + + return $.ajax({ + type: "GET", + url: "/api/schools/" + id + '/invitations?' + $.param(options), + dataType: "json", + contentType: 'application/json' + }); + } + + function createSchoolInvitation(options) { + + var id = getId(options); + + return $.ajax({ + type: "POST", + url: "/api/schools/" + id + '/invitations?' + $.param(options), + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }); + } + + function deleteSchoolInvitation(options) { + + var id = getId(options); + + return $.ajax({ + type: "DELETE", + url: "/api/schools/" + id + '/invitations/' + options.invitation_id, + dataType: "json", + contentType: 'application/json' + }); + } + + function resendSchoolInvitation(options) { + + var id = getId(options); + + return $.ajax({ + type: "POST", + url: "/api/schools/" + id + '/invitations/' + options.invitation_id + '/resend', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }); + } + + function deleteSchoolStudent(options) { + + var id = getId(options); + + return $.ajax({ + type: "DELETE", + url: "/api/schools/" + id + '/students/' + options.student_id, + dataType: "json", + contentType: 'application/json' + }); + } + + function deleteSchoolTeacher(options) { + + var id = getId(options); + + return $.ajax({ + type: "DELETE", + url: "/api/schools/" + id + '/teachers/' + options.teacher_id, + dataType: "json", + contentType: 'application/json' + }); + } + + function getRetailer(options) { + + var id = getId(options); + return $.ajax({ + type: "GET", + url: "/api/retailers/" + id, + dataType: "json", + contentType: 'application/json' + }); + } + + function updateRetailer(options) { + var id = getId(options); + return $.ajax({ + type: "POST", + url: '/api/retailers/' + id, + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + function updateRetailerAvatar(options) { + var id = getId(options); + + var original_fpfile = options['original_fpfile']; + var cropped_fpfile = options['cropped_fpfile']; + var cropped_large_fpfile = options['cropped_large_fpfile']; + var crop_selection = options['crop_selection']; + + logger.debug(JSON.stringify({ + original_fpfile: original_fpfile, + cropped_fpfile: cropped_fpfile, + cropped_large_fpfile: cropped_large_fpfile, + crop_selection: crop_selection + })); + + var url = "/api/retailers/" + id + "/avatar"; + return $.ajax({ + type: "POST", + dataType: "json", + url: url, + contentType: 'application/json', + processData: false, + data: JSON.stringify({ + original_fpfile: original_fpfile, + cropped_fpfile: cropped_fpfile, + cropped_large_fpfile: cropped_large_fpfile, + crop_selection: crop_selection + }) + }); + } + + function deleteRetailerAvatar(options) { + var id = getId(options); + + var url = "/api/retailers/" + id + "/avatar"; + return $.ajax({ + type: "DELETE", + dataType: "json", + url: url, + contentType: 'application/json', + processData: false + }); + } + + function generateRetailerFilePickerPolicy(options) { + var id = getId(options); + var handle = options && options["handle"]; + var convert = options && options["convert"] + + var url = "/api/retailers/" + id + "/filepicker_policy"; + + return $.ajax(url, { + data: {handle: handle, convert: convert}, + dataType: 'json' + }); + } + + function listRetailerInvitations(options) { + + var id = getId(options); + + return $.ajax({ + type: "GET", + url: "/api/retailers/" + id + '/invitations?' + $.param(options), + dataType: "json", + contentType: 'application/json' + }); + } + + function createRetailerInvitation(options) { + + var id = getId(options); + + return $.ajax({ + type: "POST", + url: "/api/retailers/" + id + '/invitations?' + $.param(options), + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }); + } + + function deleteRetailerInvitation(options) { + + var id = getId(options); + + return $.ajax({ + type: "DELETE", + url: "/api/retailers/" + id + '/invitations/' + options.invitation_id, + dataType: "json", + contentType: 'application/json' + }); + } + + function resendRetailerInvitation(options) { + + var id = getId(options); + + return $.ajax({ + type: "POST", + url: "/api/retaiers/" + id + '/invitations/' + options.invitation_id + '/resend', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }); + } + + function deleteRetailerStudent(options) { + + var id = getId(options); + + return $.ajax({ + type: "DELETE", + url: "/api/retailers/" + id + '/students/' + options.student_id, + dataType: "json", + contentType: 'application/json' + }); + } + + function deleteRetailerTeacher(options) { + + var id = getId(options); + + return $.ajax({ + type: "DELETE", + url: "/api/retailers/" + id + '/teachers/' + options.teacher_id, + dataType: "json", + contentType: 'application/json' + }); + } + + function listTeacherDistributions(options) { + + if (!options) { + options = {} + } + + return $.ajax({ + type: "GET", + url: "/api/teacher_distributions?" + $.param(options), + dataType: "json", + contentType: 'application/json' + }); + } + + function createReview(options) { + + return $.ajax({ + type: "POST", + url: '/api/reviews', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options), + }); + } + + function askSearchHelp(options) { + + return $.ajax({ + type: "POST", + url: '/api/teachers/search_help', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options), + }) + } + + function ratingDecision(options) { + return $.ajax({ + type: "GET", + url: '/api/lesson_sessions/rating_decision?' + $.param(options), + dataType: "json", + contentType: 'application/json' + }) + } + + function posaActivate(options) { + var slug = options.slug + delete options.slug + + return $.ajax({ + type: "POST", + url: '/api/posa/' + slug + '/activate', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options), + }) + } + + function posaClaim(options) { + + return $.ajax({ + type: "POST", + url: '/api/posa/claim', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options), + }) + } + + function sendRetailerCustomerEmail(options) { + options = options || {} + var retailerId = options.retailer + delete options.retailer + + return $.ajax({ + type: 'POST', + url: '/api/retailers/' + retailerId + '/customer_email', + dataType: 'json', + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + function paypalDetail(options) { + options = options || {} + return $.ajax({ + type: 'POST', + url: '/api/paypal/checkout/detail', + dataType: 'json', + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + function paypalPlaceOrder(options) { + options = options || {} + return $.ajax({ + type: 'POST', + url: '/api/paypal/checkout/confirm', + dataType: 'json', + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + function createLiveStream(musicSessionId) { + return $.ajax({ + type: "POST", + url: '/api/sessions/' + musicSessionId + '/livestream', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify({}) + }) + } + + function liveStreamTransition(musicSessionId, broadcastStatus) { + return $.ajax({ + type: "POST", + url: '/api/sessions/' + musicSessionId + '/livestream/transition', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify({broadcastStatus: broadcastStatus}) + }) + } + + function getLiveStream(musicSessionId) { + return $.ajax({ + type: "GET", + url: '/api/sessions/' + musicSessionId + '/livestream', + dataType: "json", + contentType: 'application/json' + }) + } + + + function initialize() { + return self; + } + + // Expose publics + this.initialize = initialize; + this.legacyCreateSession = legacyCreateSession; + this.createScheduledSession = createScheduledSession; + this.uploadMusicNotations = uploadMusicNotations; + this.getMusicNotation = getMusicNotation; + this.deleteMusicNotation = deleteMusicNotation; + this.getBroadcastNotification = getBroadcastNotification; + this.quietBroadcastNotification = quietBroadcastNotification; + this.legacyJoinSession = legacyJoinSession; + this.joinSession = joinSession; + this.cancelSession = cancelSession; + this.updateScheduledSession = updateScheduledSession; + this.getUserDetail = getUserDetail; + this.getUserJamBlasters = getUserJamBlasters; + this.getUserAuthorizations = getUserAuthorizations; + this.getGoogleAuth = getGoogleAuth; + this.getUserProfile = getUserProfile; + this.getAffiliatePartnerData = getAffiliatePartnerData; + this.postAffiliatePartnerData = postAffiliatePartnerData; + this.createAffiliatePartner = createAffiliatePartner; + this.getLinks = getLinks; + this.getAffiliateSignups = getAffiliateSignups; + this.getAffiliateMonthly = getAffiliateMonthly; + this.getAffiliateQuarterly = getAffiliateQuarterly; + this.getAffiliatePayments = getAffiliatePayments; + this.getCities = getCities; + this.getRegions = getRegions; + this.getCountries = getCountries; + this.getResolvedLocation = getResolvedLocation; + this.getInstruments = getInstruments; + this.getGenres = getGenres; + this.getSubjects = getSubjects; + this.getLanguages = getLanguages; + this.updateUdpReachable = updateUdpReachable; + this.updateNetworkTesting = updateNetworkTesting; + this.updateAvatar = updateAvatar; + this.deleteAvatar = deleteAvatar; + this.getFilepickerPolicy = getFilepickerPolicy; + this.getFriends = getFriends; + this.removeFriend = removeFriend; + this.addLike = addLike; + this.removeLike = removeLike; + this.addFollowing = addFollowing; + this.removeFollowing = removeFollowing; + this.getFollowings = getFollowings; + this.getFollowers = getFollowers; + this.getBands = getBands; + this.getBandFollowers = getBandFollowers; + this.findActiveSessions = findActiveSessions; + this.findInactiveSessions = findInactiveSessions; + this.findScheduledSessions = findScheduledSessions; + this.findScheduledRsvpSessions = findScheduledRsvpSessions; + this.updateSession = updateSession; + this.getSessionHistory = getSessionHistory; + this.addSessionComment = addSessionComment; + this.addSessionInfoComment = addSessionInfoComment; + this.addSessionLike = addSessionLike; + this.getRsvpRequests = getRsvpRequests; + this.submitRsvpRequest = submitRsvpRequest; + this.updateRsvpRequest = updateRsvpRequest; + this.cancelRsvpRequest = cancelRsvpRequest; + this.getOpenSessionSlots = getOpenSessionSlots; + this.addRecordingComment = addRecordingComment; + this.addRecordingLike = addRecordingLike; + this.addPlayablePlay = addPlayablePlay; + this.getSession = getSession; + this.deleteParticipant = deleteParticipant; + this.getClientDownloads = getClientDownloads; + this.createEmailInvitations = createEmailInvitations; + this.createMusicianInvite = createMusicianInvite; + this.getMusicianInvites = getMusicianInvites; + this.postFeedback = postFeedback; + this.getFeeds = getFeeds; + this.getUserSyncs = getUserSyncs; + this.getUserSync = getUserSync; + this.serverHealthCheck = serverHealthCheck; + this.sendFriendRequest = sendFriendRequest; + this.getFriendRequest = getFriendRequest; + this.acceptFriendRequest = acceptFriendRequest; + this.signout = signout; + this.userDownloadedClient = userDownloadedClient; + this.userCertifiedGear = userCertifiedGear; + this.userSocialPromoted = userSocialPromoted; + this.userOpenedJamTrackWebPlayer = userOpenedJamTrackWebPlayer; + this.postUserEvent = postUserEvent; + this.createJoinRequest = createJoinRequest; + this.updateJoinRequest = updateJoinRequest; + this.updateUser = updateUser; + this.startRecording = startRecording; + this.stopRecording = stopRecording; + this.getRecording = getRecording; + this.getRecordedTrack = getRecordedTrack; + this.getRecordedBackingTrack = getRecordedBackingTrack; + this.getClaimedRecordings = getClaimedRecordings; + this.getClaimedRecording = getClaimedRecording; + this.updateClaimedRecording = updateClaimedRecording; + this.deleteClaimedRecording = deleteClaimedRecording; + this.deleteRecordingClaim = deleteRecordingClaim; + this.claimRecording = claimRecording; + this.startPlayClaimedRecording = startPlayClaimedRecording; + this.stopPlayClaimedRecording = stopPlayClaimedRecording; + this.markMixdownActive = markMixdownActive; + this.createMixdown = createMixdown; + this.editMixdown = editMixdown; + this.deleteMixdown = deleteMixdown; + this.enqueueMixdown = enqueueMixdown; + this.getMixdown = getMixdown; + this.getMixdownPackage = getMixdownPackage; + this.openJamTrack = openJamTrack + this.openBackingTrack = openBackingTrack + this.closeBackingTrack = closeBackingTrack + this.closeMetronome = closeMetronome; + this.closeJamTrack = closeJamTrack; + this.openMetronome = openMetronome; + this.closeMetronome = closeMetronome; + this.discardRecording = discardRecording; + this.putTrackSyncChange = putTrackSyncChange; + this.createBand = createBand; + this.updateBand = updateBand; + this.updateBandPhoto = updateBandPhoto; + this.deleteBandPhoto = deleteBandPhoto; + this.deleteBand = deleteBand; + this.getBandPhotoFilepickerPolicy = getBandPhotoFilepickerPolicy; + this.getBand = getBand; + this.validateBand = validateBand; + this.getTeacher = getTeacher; + this.updateTeacher = updateTeacher; + this.deleteTeacher = deleteTeacher; + this.updateFavorite = updateFavorite; + this.createBandInvitation = createBandInvitation; + this.updateBandInvitation = updateBandInvitation; + this.removeBandMember = removeBandMember; + this.getBandMembers = getBandMembers; + this.login = login; + this.getShareSession = getShareSession; + this.getShareRecording = getShareRecording; + this.tweet = tweet; + this.createFbInviteUrl = createFbInviteUrl; + this.createTextMessage = createTextMessage; + this.getTextMessages = getTextMessages; + this.getNotifications = getNotifications; + this.createChatMessage = createChatMessage; + this.getChatMessages = getChatMessages; + this.createDiagnostic = createDiagnostic; + this.getLatencyTester = getLatencyTester; + this.updateAudioLatency = updateAudioLatency; + this.getJamTrack = getJamTrack; + this.getJamTrackWithArtistInfo = getJamTrackWithArtistInfo; + this.getJamTracks = getJamTracks; + this.autocompleteJamTracks = autocompleteJamTracks; + this.getJamTrackArtists = getJamTrackArtists; + this.getPurchasedJamTracks = getPurchasedJamTracks; + this.getPaymentHistory = getPaymentHistory; + this.getSalesHistory = getSalesHistory; + this.getJamTrackRight = getJamTrackRight; + this.enqueueJamTrack = enqueueJamTrack; + this.getBackingTracks = getBackingTracks; + this.addJamtrackToShoppingCart = addJamtrackToShoppingCart; + this.addGiftCardToShoppingCart = addGiftCardToShoppingCart; + this.getShoppingCarts = getShoppingCarts; + this.removeShoppingCart = removeShoppingCart; + this.clearShoppingCart = clearShoppingCart; + this.getRecurlyAccount = getRecurlyAccount; + this.createRecurlyAccount = createRecurlyAccount; + this.getBillingInfo = getBillingInfo; + this.updateBillingInfo = updateBillingInfo; + this.placeOrder = placeOrder; + this.searchMusicians = searchMusicians; + this.searchTeachers = searchTeachers; + this.resendBandInvitation = resendBandInvitation; + this.getMount = getMount; + this.createSourceChange = createSourceChange; + this.validateUrlSite = validateUrlSite; + this.markRecordedBackingTrackSilent = markRecordedBackingTrackSilent; + this.addRecordingTimeline = addRecordingTimeline; + this.addRecordingVideoData = addRecordingVideoData; + this.deleteRecordingVideoData = deleteRecordingVideoData; + this.getMusicianSearchFilter = getMusicianSearchFilter; + this.postMusicianSearchFilter = postMusicianSearchFilter; + this.getBandSearchFilter = getBandSearchFilter; + this.postBandSearchFilter = postBandSearchFilter; + this.playJamTrack = playJamTrack; + this.createSignupHint = createSignupHint; + this.createRedirectHint = createRedirectHint; + this.createAlert = createAlert; + this.redeemGiftCard = redeemGiftCard; + this.signup = signup; + this.portOverCarts = portOverCarts; + this.bookLesson = bookLesson; + this.attachRecordingToLesson = attachRecordingToLesson; + this.getTestDrivePackageChoice = getTestDrivePackageChoice; + this.getLessonBooking = getLessonBooking; + this.getUnprocessedLesson = getUnprocessedLesson; + this.getUnprocessedLessonOrIntent = getUnprocessedLessonOrIntent; + this.acceptLessonBooking = acceptLessonBooking; + this.cancelLessonBooking = cancelLessonBooking; + this.counterLessonBooking = counterLessonBooking; + this.submitStripe = submitStripe; + this.getLessonSessions = getLessonSessions; + this.getUncollectables = getUncollectables; + this.getLesson = getLesson; + this.getLessonAnalysis = getLessonAnalysis; + this.updateLessonSessionUnreadMessages = updateLessonSessionUnreadMessages; + this.checkLessonCancel = checkLessonCancel; + this.checkLessonReschedule = checkLessonReschedule; + this.getTestDriveStatus = getTestDriveStatus; + this.createTeacherIntent = createTeacherIntent; + this.getSchool = getSchool; + this.updateSchool = updateSchool; + this.updateSchoolAvatar = updateSchoolAvatar; + this.deleteSchoolAvatar = deleteSchoolAvatar; + this.generateSchoolFilePickerPolicy = generateSchoolFilePickerPolicy; + this.listSchoolInvitations = listSchoolInvitations; + this.createSchoolInvitation = createSchoolInvitation; + this.deleteSchoolInvitation = deleteSchoolInvitation; + this.resendSchoolInvitation = resendSchoolInvitation; + this.deleteSchoolTeacher = deleteSchoolTeacher; + this.deleteSchoolStudent = deleteSchoolStudent; + this.getRetailer = getRetailer; + this.updateRetailer = updateRetailer; + this.updateRetailerAvatar = updateRetailerAvatar; + this.deleteRetailerAvatar = deleteRetailerAvatar; + this.generateRetailerFilePickerPolicy = generateRetailerFilePickerPolicy; + this.listRetailerInvitations = listRetailerInvitations; + this.createRetailerInvitation = createRetailerInvitation; + this.deleteRetailerInvitation = deleteRetailerInvitation; + this.resendRetailerInvitation = resendRetailerInvitation; + this.deleteRetailerTeacher = deleteRetailerTeacher; + this.deleteRetailerStudent = deleteRetailerStudent; + this.listTeacherDistributions = listTeacherDistributions; + this.lessonStartTime = lessonStartTime; + this.createReview = createReview; + this.askSearchHelp = askSearchHelp; + this.ratingDecision = ratingDecision; + this.posaActivate = posaActivate; + this.posaClaim = posaClaim; + this.sendRetailerCustomerEmail = sendRetailerCustomerEmail; + this.paypalDetail = paypalDetail; + this.paypalPlaceOrder = paypalPlaceOrder; + this.createLiveStream = createLiveStream; + this.liveStreamTransition = liveStreamTransition; + this.getLiveStream = getLiveStream; + return this; + }; +})(window, jQuery); diff --git a/web/app/assets/javascripts/react-components.js b/web/app/assets/javascripts/react-components.js index 8a50c5178..d91c2db4b 100644 --- a/web/app/assets/javascripts/react-components.js +++ b/web/app/assets/javascripts/react-components.js @@ -22,6 +22,7 @@ //= require ./react-components/stores/BrowserMediaStore //= require ./react-components/stores/RecordingStore //= require ./react-components/stores/VideoStore +//= require ./react-components/stores/VideoLiveStreamStore //= require ./react-components/stores/SessionStore //= require ./react-components/stores/SessionStatsStore //= require ./react-components/stores/BroadcastStore diff --git a/web/app/assets/javascripts/react-components/PopupVideoLiveStream.js.jsx.coffee b/web/app/assets/javascripts/react-components/PopupVideoLiveStream.js.jsx.coffee new file mode 100644 index 000000000..7a1b5856b --- /dev/null +++ b/web/app/assets/javascripts/react-components/PopupVideoLiveStream.js.jsx.coffee @@ -0,0 +1,187 @@ +context = window +logger = context.JK.logger +rest = context.JK.Rest() + +mixins = [] + +# make sure this is actually us opening the window, not someone else (by checking for MixerStore) + +# this check ensures we attempt to listen if this component is created in a popup +reactContext = if window.opener? then window.opener else window + +accessOpener = false +if window.opener? + try + m = window.opener.MixerStore + accessOpener = true + catch e + reactContext = window + +VideoLiveStreamStore = reactContext.VideoLiveStreamStore +VideoLiveStreamActions = reactContext.VideoLiveStreamActions +AppActions = reactContext.AppActions + +if accessOpener + mixins.push(Reflux.listenTo(VideoLiveStreamStore,"onVideoLiveStreamChanged")) + +@PopupVideoLiveStream = React.createClass({ + mixins: mixins + + onVideoLiveStreamChanged: (videoLiveStream) -> + if @unloaded + return + + logger.debug("onVideoLiveStreamChanged", videoLiveStream) + this.setState({videoLiveStream: videoLiveStream}) + + render: () -> + + # there are a few initial states: if auth is null, we don't know yet (and are checking against the server) + # if auth is set, then we can show the upload btn + # and if auth == false, then we need the user to try and log in + + if @state.auth == false + action = `` + instructions = `

To upload this recording to YouTube, you must give JamKazam the necessary access to your YouTube account by clicking the button below.

` + + else if @state.videoLiveStream + + videoLiveStream = @state.videoLiveStream + if videoLiveStream.broadcast? + + controlsUrl = "https://www.youtube.com/live_event_analytics?v=" + videoLiveStream.broadcast.id + videoUrl = "https://www.youtube.com/watch?v=" + videoLiveStream.broadcast.id + controlLink = `Open Broadcast Controls` + videoLink = `Open Video Page` + + if videoLiveStream.errorMessage + action = null + instructions = `

The stream setup failed. Reason: ({videoLiveStream.errorMessage})

` + else if @state.auth == false + action = `` + instructions = `

To upload this recording to YouTube, you must give JamKazam the necessary access to your YouTube account by clicking the button below.

` + else if videoLiveStream.streaming + action = `
STOP LIVECASTING
` + instructions = `

{videoLink}{controlLink}

` + else if videoLiveStream.creatingBroadcast + action = null + instructions = `

Synchronizing with YouTube

` + else if videoLiveStream.waitingOnReady + action = null + instructions = `

Synchronizing with YouTube ... waiting on stream setup

` + else if videoLiveStream.waitingOnTesting || videoLiveStream.transitioningTesting + action = null + instructions = `

Synchronizing with YouTube ... stream is ready ... skipping preview

` + else if videoLiveStream.waitingOnLive + action = null + instructions = `

Synchronizing with YouTube ... stream is ready ... waiting to go live

` + else if !@state.initiated + action = `START BROADCASTING` + if videoLiveStream.broadcast + instructions = `

Click 'Start Broadcasting' to setup a live streaming session on YouTube.

` + else + instructions = `

Press 'Start Broadcasting' to start broadcasting on YouTube.

` + else if @state.initiated + instructions = `

Streaming initiated. Please wait...

` + else + name = null + action = null + instructions = `

UNKNOWN STATE: {JSON.stringify(videoLiveStream)}

` + else + name = 'Loading...' + action = null + + `
+

Live Stream Video

+ {instructions} +
+ {action} +
+
` + + getInitialState: () -> + {auth: null, initiated: false} + + startBroadcasting: (e) -> + e.preventDefault() + VideoLiveStreamActions.startLiveStreaming() + @setState({initiated: true}) + + watchVideo: (e) -> + e.preventDefault() + $link = $(e.target) + AppActions.openExternalUrl($link.attr('href')) + + onCloseRequested: (e) -> + e.preventDefault() + window.close() + + startGoogleLogin: (e) -> + e.preventDefault() + + logger.debug("Starting google login") + window._oauth_win = window.open("/auth/google_login", "Log In to Google", "height=700,width=500,menubar=no,resizable=no,status=no"); + window._oauth_callback = @oauthCallback + + oauthCallback: () -> + window._oauth_win.close() + @checkAuth() + + checkAuth:() -> + rest.getGoogleAuth() + .done((auth) => + if auth.auth? + @setState({auth: auth.auth}) + else + @setState({auth: false}) + ) + .fail(() => + @setState({errorReason: 'Unable to fetch user authorization'}) + ) + + componentDidMount: () -> + + $(window).unload(@windowUnloaded) + + @checkAuth() + + VideoLiveStreamActions.loadBroadcast(gon.session_id) + + @resizeWindow() + + # this is necessary due to whatever the client's rendering behavior is. + setTimeout(@resizeWindow, 300) + + shouldComponentUpdate: () -> + return !@unloaded + + componentDidUpdate: () -> + @resizeWindow() + setTimeout(@resizeWindow, 1000) + + resizeWindow: () => + $container = $('#minimal-container') + width = $container.width() + height = $container.height() + + # there is 20px or so of unused space at the top of the page. can't figure out why it's there. (above #minimal-container) + #mysteryTopMargin = 20 + mysteryTopMargin = 0 + # deal with chrome in real browsers + offset = (window.outerHeight - window.innerHeight) + mysteryTopMargin + + # handle native client chrome that the above outer-inner doesn't catch + #if navigator.userAgent.indexOf('JamKazam') > -1 + + #offset += 25 + + width = 100 if width < 100 + height = 100 if height < 100 + + window.resizeTo(width, height + offset) + + windowUnloaded: () -> + @unloaded = true + window.unloaded = true + VideoLiveStreamActions.popupClosed() +}) \ No newline at end of file diff --git a/web/app/assets/javascripts/react-components/actions/VideoActions.js.coffee b/web/app/assets/javascripts/react-components/actions/VideoActions.js.coffee index a50ac1cb9..92f16b0bd 100644 --- a/web/app/assets/javascripts/react-components/actions/VideoActions.js.coffee +++ b/web/app/assets/javascripts/react-components/actions/VideoActions.js.coffee @@ -15,4 +15,5 @@ context = window checkPromptConfigureVideo: {} setVideoEnabled: {} refreshVideoState: {} + startLiveStream: {} }) \ No newline at end of file diff --git a/web/app/assets/javascripts/react-components/actions/VideoLiveStreamActions.js.coffee b/web/app/assets/javascripts/react-components/actions/VideoLiveStreamActions.js.coffee new file mode 100644 index 000000000..8ef50d5be --- /dev/null +++ b/web/app/assets/javascripts/react-components/actions/VideoLiveStreamActions.js.coffee @@ -0,0 +1,9 @@ +context = window + +@VideoLiveStreamActions = Reflux.createActions({ + startLiveStream: {} + streamStarted: {} + popupClosed: {} + loadBroadcast: {} + startLiveStreaming: {} +}) \ No newline at end of file diff --git a/web/app/assets/javascripts/react-components/stores/CallbackStore.js.coffee b/web/app/assets/javascripts/react-components/stores/CallbackStore.js.coffee index f5b81df87..d407b27d3 100644 --- a/web/app/assets/javascripts/react-components/stores/CallbackStore.js.coffee +++ b/web/app/assets/javascripts/react-components/stores/CallbackStore.js.coffee @@ -4,6 +4,7 @@ logger = context.JK.logger RecordingActions = @RecordingActions SessionActions = @SessionActions JamBlasterActions = @JamBlasterActions +VideoLiveStreamActions = @VideoLiveStreamActions #window.StupidCallback: () => # alert("STUPID CALLBACK") @@ -24,6 +25,8 @@ JamBlasterActions = @JamBlasterActions console.log("GENERIC CALLBACK CALLED: ", map) if map.cmd == 'join_session' SessionActions.joinSession(map['music_session_id']) + else if map.cmd == 'start_livestream' + VideoLiveStreamActions.startLiveStream() else if map.cmd == 'client_pair_state' JamBlasterActions.pairState(map) else if map.cmd == 'jamblaster_tracks_updated' @@ -31,6 +34,5 @@ JamBlasterActions = @JamBlasterActions else if map.cmd == 'file_xfer_from_parent' if map.filename && map.filename.indexOf('RT-mix.wav') > -1 RecordingActions.mixTransferred() - } ) diff --git a/web/app/assets/javascripts/react-components/stores/VideoLiveStreamStore.js.coffee b/web/app/assets/javascripts/react-components/stores/VideoLiveStreamStore.js.coffee new file mode 100644 index 000000000..f5ac4854f --- /dev/null +++ b/web/app/assets/javascripts/react-components/stores/VideoLiveStreamStore.js.coffee @@ -0,0 +1,265 @@ +context = window +logger = context.JK.logger +rest = context.JK.Rest() +EVENTS = context.JK.EVENTS +NAMED_MESSAGES = context.JK.NAMED_MESSAGES + +VideoLiveStreamActions = @VideoLiveStreamActions + +@VideoLiveStreamStore = Reflux.createStore( + { + listenables: VideoLiveStreamActions + logger: context.JK.logger + creatingBroadcast: false + + init: -> + this.listenTo(context.AppStore, this.onAppInit) + + onAppInit: (@app) -> + + onPopupClosed: () -> + + if @childWindow? + @childWindow = null + + logger.debug("Popup closed") + context.jamClient.StopLiveStreaming() + @streaming = false + @onRefresh() + + + onRefresh: () -> + @state = { + creatingBroadcast: @creatingBroadcast, + createdStream: @createdStream, + createStreamError: @createStreamError, + waitingForReady: @waitingForReady, + waitingOnTesting: @waitingOnTesting, + waitingOnLive: @waitingOnLive, + transitioningTesting: @transitioningTesting, + streaming: @streaming, + errorMessage: @errorMessage, + broadcast: @broadcast + } + this.trigger(@state) + + onStartLiveStream: () -> + @creatingBroadcast = false + @createdStream = false + @createStreamError = false + @transitioningTesting = false + @waitingForReady = false + @waitingOnLive = false + @waitingOnTesting = false + @errorMessage = null + @streaming = false + + @logger.debug("onStartLiveStream") + @onRefresh() + + if @childWindow? + logger.debug("show live stream popup being closed automatically") + @childWindow.close() + @childWindow = null + + @childWindow = window.open("/popups/video/stream/" + context.SessionStore.id(), 'Video Live Stream', 'scrollbars=yes,toolbar=no,status=no,height=155,width=350') + + startLiveStreaming: () -> + @logger.debug("user requests live stream") + @createLiveStream() + + # do not use; here until can remove + startGoogleLogin: (e) -> + + @logger.debug("Starting google login") + window._oauth_win = window.open("/auth/google_login", "Log In to Google", "height=700,width=500,menubar=no,resizable=no,status=no"); + window._oauth_callback = @oauthCallback + + oauthCallback: () -> + @creatingBroadcast = true + @logger.debug("oauthCallback... checking auth") + window._oauth_win.close() + @checkAuth() + + checkAuth:() -> + rest.getGoogleAuth() + .done((auth) => + @logger.debug("check Auth is done", auth) + if auth.auth? + @createLiveStream() + else + @creatingBroadcast = false + @onRefresh() + # alert to user + ) + .fail(() => + @creatingBroadcast = false + @onRefresh() + # lert to user + ) + + loadBroadcast: (sessionId) -> + @broadcast = null + @onRefresh() + @fetchBroadcast(sessionId) + + fetchBroadcast: (sessionId) -> + rest.getLiveStream(sessionId) + .done((broadcast) => + @broadcast = broadcast + @onRefresh() + ) + .fail((jqXHR) => + logger.error("unabe to fetch broadcast", jqXHR.responseText) + @onRefresh() + ) + + createLiveStream: () -> + + @creatingBroadcast = true + + rest.createLiveStream(context.SessionStore.id()) + .done((broadcast) => + @creatingBroadcast = false + @onRefresh() + success = context.jamClient.StartLiveStreaming(broadcast.stream_name) + + if success + @createdStream = true + @waitingForReady = true + @transitionTimeout = new Date().getTime() + 10000 # die in 10 seconds + @onRefresh() + setTimeout(() => + @waitForReady() + , 1000) + + else + @createStreamError = true + @onRefresh() + ) + .fail(() => + @creatingBroadcast = false + @onRefresh() + ) + + waitForReady: () -> + rest.getLiveStream(context.SessionStore.id()) + .done((broadcast) => + if broadcast.broadcast_status == 'ready' + @waitingForReady = false + @transitionTesting() + else + if new Date().getTime() > @transitionTimeout + # uh oh. waited fo ra while; stream never became ready + @errorMessage = 'YouTube never indicated stream is ready for testing' + @waitingForReady = false + @onRefresh() + else + setTimeout(() => + @waitForReady() + , 1000) + ) + .fail(() => + @waitingForReady = false + @errorMessage = 'Could not check status of YouTube broadcast' + context.jamClient.StopLiveStreaming() + @streaming = false + @onRefresh() + ) + + transitionTesting: () -> + @transitioningTesting = true + @onRefresh() + + rest.liveStreamTransition(context.SessionStore.id(), 'testing') + .done((broadcast) => + @transitioningTesting = false + @waitingOnTesting = true + @transitionTimeout = new Date().getTime() + 20000 # die in 20 seconds + setTimeout(() => + @waitForTesting() + , 1000) + ) + .fail(() => + @transitioningTesting = false + @errorMessage = 'Could not transition live stream to "testing"' + context.jamClient.StopLiveStreaming() + @streaming = false + @onRefresh() + ) + + transitionLive: () -> + @transitioningLive = true + @onRefresh() + + rest.liveStreamTransition(context.SessionStore.id(), 'live') + .done((broadcast) => + @transitioningLive = false + @waitingOnLive = true + @transitionTimeout = new Date().getTime() + 20000 # die in 20 seconds + setTimeout(() => + @waitForLive() + , 1000) + ) + .fail(() => + @transitioningLive = false + @errorMessage = 'Could not transition live stream to "live"' + context.jamClient.StopLiveStreaming() + @streaming = false + @onRefresh() + ) + + + waitForTesting: () -> + rest.getBroadcast(context.SessionStore.id()) + .done((broadcast) => + if broadcast.broadcast_status == 'testing' + @waitingOnTesting = false + @transitionLive() + else + if new Date().getTime() > @transitionTimeout + # uh oh. waited fo ra while; stream never became ready + @errorMessage = 'YouTube never indicated stream converted to testing' + @waitingOnTesting = false + @onRefresh() + else + setTimeout(() => + @waitForTesting() + , 1000) + ) + .fail(() => + @waitingForTesting = false + @errorMessage = 'Could not check status of YouTube broadcast' + context.jamClient.StopLiveStreaming() + @streaming = false + @onRefresh() + ) + + waitForLive: () -> + rest.getBroadcast(context.SessionStore.id()) + .done((broadcast) => + if broadcast.broadcast_status == 'live' + @waitingOnLive = false + @streaming = true + console.log("BROADCAST TIME", broadcast) + @onRefresh() + else + if new Date().getTime() > @transitionTimeout + # uh oh. waited fo ra while; stream never became ready + @errorMessage = 'YouTube never indicated stream converted to live' + @waitingOnLive = false + @onRefresh() + else + setTimeout(() => + @waitForLive() + , 1000) + ) + .fail(() => + @waitingForLive = false + @errorMessage = 'Could not check status of YouTube broadcast' + context.jamClient.StopLiveStreaming() + @streaming = false + @onRefresh() + ) + } +) \ No newline at end of file diff --git a/web/app/assets/javascripts/react-components/stores/VideoStore.js.coffee b/web/app/assets/javascripts/react-components/stores/VideoStore.js.coffee index d0923cda7..e8b0e1b37 100644 --- a/web/app/assets/javascripts/react-components/stores/VideoStore.js.coffee +++ b/web/app/assets/javascripts/react-components/stores/VideoStore.js.coffee @@ -1,6 +1,7 @@ $ = jQuery context = window logger = context.JK.logger +rest = context.JK.Rest() EVENTS = context.JK.EVENTS NAMED_MESSAGES = context.JK.NAMED_MESSAGES @@ -236,5 +237,6 @@ BackendToFrontendFPS = { isVideoEnabled:() -> return @videoEnabled + } ) diff --git a/web/app/assets/stylesheets/dialogs/liveStreamingDialog.scss b/web/app/assets/stylesheets/dialogs/liveStreamingDialog.scss new file mode 100644 index 000000000..1c59ed171 --- /dev/null +++ b/web/app/assets/stylesheets/dialogs/liveStreamingDialog.scss @@ -0,0 +1,57 @@ +@import "client/common"; + +#live-streaming-dialog { + width: 600px; + + h2 { + color:white; + margin-bottom:10px; + font-size:16px; + } + .dialog-inner { + width: auto; + height:calc(100% - 29px); + padding-bottom:75px; + } + + .field { + margin-bottom:10px; + } + + input { + display:inline-block; + } + label { + display:inline-block; + } + .iradio_minimal { + display:inline-block; + margin-right: 5px; + top: 4px; + } + + div[data-react-class="LiveStreamingDialog"] { + + } + .actions { + position:absolute; + right:0; + bottom:0; + margin:0 20px 30px 0; + } + .countdown-msg { + margin-top:30px; + } + .countdown { + color:white; + font-size:18px; + font-weight:bold; + padding:0 10px; + width:30px; + display:inline-block; + text-align:center; + } + .message { + margin-top:20px; + } +} \ No newline at end of file diff --git a/web/app/assets/stylesheets/minimal/video_live_stream.scss b/web/app/assets/stylesheets/minimal/video_live_stream.scss new file mode 100644 index 000000000..75120cdef --- /dev/null +++ b/web/app/assets/stylesheets/minimal/video_live_stream.scss @@ -0,0 +1,58 @@ +@import "client/common"; + +body.video-live-stream{ + + position: relative; + color: $ColorTextTypical; + + #minimal-container { + padding-bottom: 20px; + height:240px; + } + + .video-uploader { + padding-left: 30px; + padding-right:30px; + } + + h3 { + margin-top:20px; + font-size:16px; + font-weight:bold; + margin-bottom:20px; + text-align:center; + line-height:125%; + } + + .control-holder { + margin: 20px 0 20px; + text-align:center; + padding-bottom:20px; + + position: absolute; + bottom: 0; + width: 100%; + left: 0; + } + + .progress-bar { + background-color:#ED3618; + border:solid 1px #000; + height:20px; + display:block; + @include border_box_sizing; + margin:20px 0; + position:relative; + } + + .percentage-progress { + position:absolute; + right:-32px; + } + + .video-url { + text-align:center; + display:block; + margin:20px 0; + } +} \ No newline at end of file diff --git a/web/app/assets/stylesheets/minimal/video_stream.scss b/web/app/assets/stylesheets/minimal/video_stream.scss index f0d276c5e..2d49838d4 100644 --- a/web/app/assets/stylesheets/minimal/video_stream.scss +++ b/web/app/assets/stylesheets/minimal/video_stream.scss @@ -7,7 +7,7 @@ body.video-stream { #minimal-container { padding-bottom: 20px; - height:240px; + height:170px; } .video-stream { @@ -55,4 +55,8 @@ body.video-stream { display:block; margin:20px 0; } + + .video-live-stream { + padding:0 20px; + } } \ No newline at end of file diff --git a/web/app/controllers/api_music_sessions_controller.rb b/web/app/controllers/api_music_sessions_controller.rb index 35d3111e2..163ab29fc 100644 --- a/web/app/controllers/api_music_sessions_controller.rb +++ b/web/app/controllers/api_music_sessions_controller.rb @@ -5,6 +5,7 @@ class ApiMusicSessionsController < ApiController # have to be signed in currently to see this screen before_filter :api_signed_in_user, :except => [ :add_like, :show, :show_history, :add_session_info_comment ] before_filter :lookup_session, only: [:show, :update, :delete, :claimed_recording_start, :claimed_recording_stop, :track_sync, :jam_track_open, :jam_track_close, :backing_track_open, :backing_track_close, :metronome_open, :metronome_close] + before_filter :lookup_perm_session, only: [:get_livestream, :create_livestream, :livestream_transition] skip_before_filter :api_signed_in_user, only: [:perf_upload] around_filter :transactions_filter, only:[:sms_index, :ams_index] @@ -648,10 +649,51 @@ class ApiMusicSessionsController < ApiController respond_with_model(@music_session) end -private + def get_livestream + unless @music_session.active_music_session.users.exists?(current_user.id) + raise JamPermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR + end + + @livestream = @music_session.get_broadcast(current_user) + + if @livestream + respond_with (@livestream), responder: ApiResponder + else + render :json => { :message => "No broadcast associated with this session" }, :status => 404 + end + end + + def create_livestream + unless @music_session.active_music_session.users.exists?(current_user.id) + raise JamPermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR + end + + @livestream = @music_session.create_stream(current_user, params[:options]) + respond_with (@livestream), responder: ApiResponder + end + + def livestream_transition + unless @music_session.active_music_session.users.exists?(current_user.id) + raise JamPermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR + end + + broadcast = @music_session.music_session.current_broadcast + + if broadcast + @livestream = @music_session.transition_broadcast(current_user, broadcast, params[:broadcastStatus]) + respond_with (@livestream), responder: ApiResponder + else + render :json => { :message => "No broadcast associated with this session" }, :status => 404 + end + end + + private def lookup_session @music_session = ActiveMusicSession.find(params[:id]) end + def lookup_perm_session + @music_session = MusicSession.find(params[:id]) + end end diff --git a/web/app/controllers/popups_controller.rb b/web/app/controllers/popups_controller.rb index 5ea8af974..6fef5b327 100644 --- a/web/app/controllers/popups_controller.rb +++ b/web/app/controllers/popups_controller.rb @@ -30,6 +30,12 @@ class PopupsController < ApplicationController end + def video_stream + @session_id = params[:session_id] + gon.session_id= @session_id + render :layout => "minimal" + end + def video_stream @session_id = params[:session_id] gon.session_id= @session_id diff --git a/web/app/views/api_music_sessions/create_livestream.rabl b/web/app/views/api_music_sessions/create_livestream.rabl new file mode 100644 index 000000000..ec62034d1 --- /dev/null +++ b/web/app/views/api_music_sessions/create_livestream.rabl @@ -0,0 +1,3 @@ +object @livestream + +extends "api_music_sessions/livestream_show" \ No newline at end of file diff --git a/web/app/views/api_music_sessions/get_livestream.rabl b/web/app/views/api_music_sessions/get_livestream.rabl new file mode 100644 index 000000000..ec62034d1 --- /dev/null +++ b/web/app/views/api_music_sessions/get_livestream.rabl @@ -0,0 +1,3 @@ +object @livestream + +extends "api_music_sessions/livestream_show" \ No newline at end of file diff --git a/web/app/views/api_music_sessions/livestream_show.rabl b/web/app/views/api_music_sessions/livestream_show.rabl new file mode 100644 index 000000000..bd9a59626 --- /dev/null +++ b/web/app/views/api_music_sessions/livestream_show.rabl @@ -0,0 +1,3 @@ +object @livestream + +attributes :id, :broadcast_status, :stream_status, :stream_name, :stream_address, :broadcast_data, :broadcast_id, :stream_id diff --git a/web/app/views/api_music_sessions/livestream_transition.rabl b/web/app/views/api_music_sessions/livestream_transition.rabl new file mode 100644 index 000000000..ec62034d1 --- /dev/null +++ b/web/app/views/api_music_sessions/livestream_transition.rabl @@ -0,0 +1,3 @@ +object @livestream + +extends "api_music_sessions/livestream_show" \ No newline at end of file diff --git a/web/app/views/dialogs/_liveStreamingDialog.html.slim b/web/app/views/dialogs/_liveStreamingDialog.html.slim new file mode 100644 index 000000000..b4e20e8ab --- /dev/null +++ b/web/app/views/dialogs/_liveStreamingDialog.html.slim @@ -0,0 +1,2 @@ +.dialog.dialog-overlay-sm.top-parent layout='dialog' layout-id='jamblaster-pairing-dialog' id='jamblaster-pairing-dialog' + = react_component 'JamBlasterPairingDialog', {} diff --git a/web/app/views/popups/video_stream.html.slim b/web/app/views/popups/video_stream.html.slim index 08a9dd556..4dfa3ba21 100644 --- a/web/app/views/popups/video_stream.html.slim +++ b/web/app/views/popups/video_stream.html.slim @@ -1,3 +1,3 @@ - provide(:page_name, 'video-stream popup') - provide(:title, 'Video Stream') -= react_component 'PopupVideoStreamer', {} \ No newline at end of file += react_component 'PopupVideoLiveStream', {} \ No newline at end of file diff --git a/web/config/routes.rb b/web/config/routes.rb index 94718c3aa..8b6f7261c 100644 --- a/web/config/routes.rb +++ b/web/config/routes.rb @@ -251,6 +251,10 @@ Rails.application.routes.draw do match '/sessions/:id/metronome/close' => 'api_music_sessions#metronome_close', :via => :post match '/sessions/:id/session_controller' => 'api_music_sessions#session_controller', :via => :post + match '/sessions/:id/livestream' => 'api_music_sessions#get_livestream', :via => :get + match '/sessions/:id/livestream' => 'api_music_sessions#create_livestream', :via => :post + match '/sessions/:id/livestream/transition' => 'api_music_sessions#livestream_transition', :via => :post + # music session tracks match '/sessions/:id/tracks' => 'api_music_sessions#track_create', :via => :post match '/sessions/:id/tracks' => 'api_music_sessions#track_sync', :via => :put diff --git a/web/lib/google_client.rb b/web/lib/google_client.rb index 649de6737..2afc1b500 100644 --- a/web/lib/google_client.rb +++ b/web/lib/google_client.rb @@ -178,6 +178,29 @@ module JamRuby end end + def transition_broadcast(user, broadcast_id, broadcastStatus) + auth = UserAuthorization.google_auth(user).first + if auth.nil? || auth.token.nil? + raise JamPermissionError, "No current google token found for user #{user}" + end + + begin + my_client = create_client + + my_client.authorization = create_authorization(auth, 'https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/youtube.force-ssl', true) + #y = my_client.discovered_api('youtube', 'v3') + response = my_client.execute!(:api_method => youtube.live_broadcasts.transition, + :parameters => {:part => 'id,contentDetails,status,snippet', :id => broadcast_id, :broadcastStatus => broadcastStatus }) + + body = JSON.parse(response.body) + puts "TRANSITION RESPONSE: #{body}" + return body + rescue Google::APIClient::ClientError => e + puts e.result.body + raise e + end + end + def get_broadcast(user, broadcast_id) auth = UserAuthorization.google_auth(user).first if auth.nil? || auth.token.nil? @@ -193,8 +216,39 @@ module JamRuby :parameters => {:part => 'id,contentDetails,status,snippet', :id => broadcast_id }) body = JSON.parse(response.body) - puts "BIND RESPONSE: #{body}" - return body["items"][0] # returns array of items. meh + puts "GET BROADCAST RESPONSE: #{body}" + if body["items"].length == 0 + nil + else + body["items"][0] # returns array of items. meh + end + rescue Google::APIClient::ClientError => e + puts e.result.body + raise e + end + end + + def get_livestream(user, stream_id) + auth = UserAuthorization.google_auth(user).first + if auth.nil? || auth.token.nil? + raise JamPermissionError, "No current google token found for user #{user}" + end + + begin + my_client = create_client + + my_client.authorization = create_authorization(auth, 'https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/youtube.force-ssl', true) + #y = my_client.discovered_api('youtube', 'v3') + response = my_client.execute!(:api_method => youtube.live_streams.list, + :parameters => {:part => 'id,snippet,cdn,status', :id => stream_id }) + + body = JSON.parse(response.body) + puts "GET LIVE STREAM RESPONSE: #{body}" + if body["items"].length == 0 + nil + else + body["items"][0] # returns array of items. meh + end rescue Google::APIClient::ClientError => e puts e.result.body raise e diff --git a/web/lib/tasks/google.rake b/web/lib/tasks/google.rake index 6b25d58b0..a6eefee3d 100644 --- a/web/lib/tasks/google.rake +++ b/web/lib/tasks/google.rake @@ -11,4 +11,76 @@ namespace :google do puts broadcast.inspect end + + task get_livestream: :environment do |task, args| + google_client = JamRuby::GoogleClient.new + music_session = MusicSession.first + user = User.find_by_email('seth@jamkazam.com') + + livestream = music_session.get_livestream(google_client, user) + + puts livestream.inspect + + # example: + #{"kind"=>"youtube#liveStream", + # "etag"=>"\"m2yskBQFythfE4irbTIeOgYYfBU/fq4yPJsfCN91Qi2Dd9VuLZ3sm9U\"", + # "id"=>"lgXe2spB8uVk-U6H_b8aSQ1495983496676422", + # "snippet"=>{"publishedAt"=>"2017-05-28T14:58:16.000Z", + # "channelId"=>"UClgXe2spB8uVk-U6H_b8aSQ", + # "title"=>"Private Test Session", "description"=>"", "isDefaultStream"=>false}, + # "cdn"=>{"format"=>"360p", "ingestionType"=>"rtmp", "ingestionInfo"=>{"streamName"=>"6axs-3zpj-0esg-d7uv", "ingestionAddress"=>"rtmp://a.rtmp.youtube.com/live2", "backupIngestionAddress"=>"rtmp://b.rtmp.youtube.com/live2?backup=1"}, "resolution"=>"360p", "frameRate"=>"30fps"}, + # "status"=>{"streamStatus"=>"active", "healthStatus"=>{"status"=>"good", "configurationIssues"=>[{"type"=>"audioBitrateHigh", "severity"=>"info", "reason"=>"Check audio settings", "description"=>"The audio stream's current bitrate of 255.00 Kbps is higher than the recommended bitrate. We recommend that you use an audio stream bitrate of 128 Kbps."}, {"type"=>"bitrateHigh", "severity"=>"info", "reason"=>"Check video settings", "description"=>"The stream's current bitrate (1286.00 Kbps) is higher than the recommended bitrate. We recommend that you use a stream bitrate of 750 Kbps."}]}}} + + end + + task get_broadcast: :environment do |task, args| + google_client = JamRuby::GoogleClient.new + music_session = MusicSession.first + user = User.find_by_email('seth@jamkazam.com') + + broadcast = music_session.get_broadcast(google_client, user) + + # example: + #{"kind"=>"youtube#liveBroadcast", + # "etag"=>"\"m2yskBQFythfE4irbTIeOgYYfBU/7ARgOe0WJLQdOvjeISlnBnnK3L0\"", + # "id"=>"4CLE1CXfKB8", + # "snippet"=>{"publishedAt"=>"2017-05-28T14:58:16.000Z", "channelId"=>"UClgXe2spB8uVk-U6H_b8aSQ", "title"=>"Private Test Session", "description"=>"Private session set up just to test things out in the session interface by myself.", "thumbnails"=>{"default"=>{"url"=>"https://i9.ytimg.com/vi/4CLE1CXfKB8/default_live.jpg?sqp=CMzXq8kF&rs=AOn4CLCo_lxnPzD52m7nQgJ7xHsyRSBLkw", "width"=>120, "height"=>90}, "medium"=>{"url"=>"https://i9.ytimg.com/vi/4CLE1CXfKB8/mqdefault_live.jpg?sqp=CMzXq8kF&rs=AOn4CLDF5tDY7i0H__d27ZTdSfbvrpgc6w", "width"=>320, "height"=>180}, "high"=>{"url"=>"https://i9.ytimg.com/vi/4CLE1CXfKB8/hqdefault_live.jpg?sqp=CMzXq8kF&rs=AOn4CLAl1XUfz8faQDBXEydsDG9D5iRe6g", "width"=>480, "height"=>360}}, "scheduledStartTime"=>"2017-05-28T14:58:17.000Z", "isDefaultBroadcast"=>false, "liveChatId"=>"Cg0KCzRDTEUxQ1hmS0I4"}, + # "status"=>{"lifeCycleStatus"=>"testing", "privacyStatus"=>"private", "recordingStatus"=>"notRecording"}, + # "contentDetails"=>{"boundStreamId"=>"lgXe2spB8uVk-U6H_b8aSQ1495983496676422", "boundStreamLastUpdateTimeMs"=>"2017-05-28T14:58:16.695Z", "monitorStream"=>{"enableMonitorStream"=>true, "broadcastStreamDelayMs"=>0, "embedHtml"=>""}, "enableEmbed"=>true, "enableDvr"=>true, "enableContentEncryption"=>false, "startWithSlate"=>false, "recordFromStart"=>true, "enableClosedCaptions"=>false, "closedCaptionsType"=>"closedCaptionsDisabled", "enableLowLatency"=>false, "projection"=>"rectangular"}} + + puts broadcast.inspect + end + + task transition_broadcast_live: :environment do |task, args| + google_client = JamRuby::GoogleClient.new + music_session = MusicSession.first + user = User.find_by_email('seth@jamkazam.com') + + + livestream = music_session.transition_broadcast(google_client, user, music_session.current_broadcast, 'live') + + puts livestream.inspect + end + + + task transition_broadcast_testing: :environment do |task, args| + google_client = JamRuby::GoogleClient.new + music_session = MusicSession.first + user = User.find_by_email('seth@jamkazam.com') + + + livestream = music_session.transition_broadcast(google_client, user, music_session.current_broadcast, 'testing') + + puts livestream.inspect + end + + task transition_broadcast_complete: :environment do |task, args| + google_client = JamRuby::GoogleClient.new + music_session = MusicSession.first + user = User.find_by_email('seth@jamkazam.com') + + livestream = music_session.transition_broadcast(google_client, user, music_session.current_broadcast, 'complete') + + puts livestream.inspect + end end diff --git a/web/lib/user_manager.rb b/web/lib/user_manager.rb index 139221801..4fb3f4cea 100644 --- a/web/lib/user_manager.rb +++ b/web/lib/user_manager.rb @@ -7,6 +7,10 @@ class UserManager < BaseManager @google_client = GoogleClient.new() end + def get_google_client + @google_client + end + # Note that almost everything can be nil here. This is because when users sign up via social media, # we don't know much about them. def signup(options)